@cdc/chart 1.3.4 → 4.22.11

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 (75) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +5 -5
  3. package/dist/cdcchart.js +6 -6
  4. package/examples/age-adjusted-rates.json +1486 -1218
  5. package/examples/case-rate-example-config.json +1 -1
  6. package/examples/covid-confidence-example-config.json +33 -33
  7. package/examples/covid-example-config.json +34 -34
  8. package/examples/covid-example-data-confidence.json +30 -30
  9. package/examples/covid-example-data.json +20 -20
  10. package/examples/cutoff-example-config.json +36 -34
  11. package/examples/cutoff-example-data.json +36 -36
  12. package/examples/date-exclusions-config.json +1 -1
  13. package/examples/dynamic-legends.json +125 -0
  14. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart-with-numbers-on-bar.json +192 -0
  15. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +231 -0
  16. package/examples/gallery/bar-chart-horizontal/horizontal-stacked.json +240 -0
  17. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +137 -0
  18. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +80 -0
  19. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +81 -0
  20. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +68 -0
  21. package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +111 -0
  22. package/examples/gallery/lollipop/lollipop-style-horizontal.json +216 -0
  23. package/examples/gallery/paired-bar/paired-bar-chart.json +196 -0
  24. package/examples/horizontal-chart.json +36 -33
  25. package/examples/horizontal-stacked-bar-chart.json +34 -34
  26. package/examples/line-chart.json +75 -75
  27. package/examples/paired-bar-data.json +16 -14
  28. package/examples/paired-bar-example.json +48 -46
  29. package/examples/paired-bar-formatted.json +36 -36
  30. package/examples/planet-chart-horizontal-example-config.json +33 -33
  31. package/examples/planet-combo-example-config.json +34 -29
  32. package/examples/planet-example-config.json +35 -33
  33. package/examples/planet-example-data.json +56 -56
  34. package/examples/planet-pie-example-config.json +28 -26
  35. package/examples/private/filters.json +170 -0
  36. package/examples/private/line-test-data.json +22 -0
  37. package/examples/private/line-test-two.json +210 -0
  38. package/examples/private/line-test.json +102 -0
  39. package/examples/private/new.json +48800 -0
  40. package/examples/private/shawn.json +1106 -0
  41. package/examples/private/test.json +10123 -10123
  42. package/examples/private/yaxis-test.json +133 -0
  43. package/examples/private/yaxis-testing.csv +27 -0
  44. package/examples/private/yaxis.json +28 -0
  45. package/examples/stacked-vertical-bar-example.json +228 -0
  46. package/examples/temp-example-config.json +61 -54
  47. package/examples/temp-example-data.json +1 -1
  48. package/package.json +2 -2
  49. package/src/CdcChart.tsx +370 -458
  50. package/src/components/BarChart.tsx +449 -441
  51. package/src/components/DataTable.tsx +164 -180
  52. package/src/components/EditorPanel.js +1066 -663
  53. package/src/components/Legend.js +284 -0
  54. package/src/components/LineChart.tsx +114 -63
  55. package/src/components/LinearChart.tsx +394 -358
  56. package/src/components/PairedBarChart.tsx +216 -135
  57. package/src/components/PieChart.tsx +106 -135
  58. package/src/components/SparkLine.js +184 -205
  59. package/src/components/useIntersectionObserver.tsx +27 -0
  60. package/src/context.tsx +3 -3
  61. package/src/data/initial-state.js +44 -7
  62. package/src/hooks/useActiveElement.js +13 -13
  63. package/src/hooks/useChartClasses.js +41 -0
  64. package/src/hooks/useColorPalette.ts +56 -63
  65. package/src/hooks/useLegendClasses.js +28 -0
  66. package/src/hooks/useReduceData.ts +69 -37
  67. package/src/hooks/useRightAxis.js +25 -0
  68. package/src/hooks/useTopAxis.js +6 -0
  69. package/src/index.html +54 -55
  70. package/src/index.tsx +13 -16
  71. package/src/scss/DataTable.scss +5 -4
  72. package/src/scss/editor-panel.scss +103 -71
  73. package/src/scss/main.scss +277 -38
  74. package/src/scss/variables.scss +1 -1
  75. package/src/components/BarStackVertical.js +0 -0
@@ -1,144 +1,225 @@
1
- import React, { useContext } from 'react';
2
- import { Group } from '@visx/group';
3
- import { Bar } from '@visx/shape';
4
- import { scaleLinear, scaleBand } from '@visx/scale';
5
- import { Text } from '@visx/text';
6
-
7
- import Context from '../context';
8
- import chroma from 'chroma-js';
1
+ import React, { useContext } from 'react'
2
+ import { Group } from '@visx/group'
3
+ import { Bar } from '@visx/shape'
4
+ import { scaleLinear, scaleBand } from '@visx/scale'
5
+ import { Text } from '@visx/text'
9
6
 
7
+ import Context from '../context'
8
+ import chroma from 'chroma-js'
10
9
 
11
10
  interface PairedBarChartProps {
12
- width: number,
13
- height: number
11
+ width: number
12
+ height: number
14
13
  }
15
14
 
16
15
  const PairedBarChart: React.FC<PairedBarChartProps> = ({ width, height }) => {
17
-
18
- const { config, colorScale, transformedData } = useContext<any>(Context);
19
-
20
- if(!config || config?.series?.length < 2) return;
21
-
22
- const data = transformedData
23
- const adjustedWidth = width;
24
- const adjustedHeight = height;
25
- const halfWidth = adjustedWidth / 2;
26
-
27
- const groupOne = {
28
- parentKey: config.dataDescription.seriesKey,
29
- dataKey: config.series[0].dataKey,
30
- color: colorScale(config.runtime.seriesLabels[config.series[0].dataKey]),
31
- max: Math.max.apply(Math, data.map(item => item[config.series[0].dataKey])),
32
- labelColor: ''
33
- }
34
-
35
- const groupTwo = {
36
- parentKey: config.dataDescription.seriesKey,
37
- dataKey: config.series[1].dataKey,
38
- color: colorScale(config.runtime.seriesLabels[config.series[1].dataKey]),
39
- max: Math.max.apply(Math, data.map(item => item[config.series[1].dataKey])),
40
- labelColor: ''
41
- }
42
-
43
- const xScale = scaleLinear({
44
- domain: [0, Math.max(groupOne.max, groupTwo.max)],
45
- range: [0, halfWidth]
46
- });
47
-
48
-
49
- const yScale = scaleBand({
50
- range: [0, adjustedHeight],
51
- domain: data.map(d => d[config.dataDescription.xKey]),
52
- padding: 0.2
53
- });
54
-
55
- // Set label color
56
- let labelColor = '#000000';
57
-
58
- if (chroma.contrast(labelColor, groupOne.color) < 4.9) {
59
- groupOne.labelColor = '#FFFFFF';
60
- }
61
-
62
- if (chroma.contrast(labelColor, groupTwo.color) < 4.9) {
63
- groupTwo.labelColor = '#FFFFFF';
64
- }
65
-
66
- return (width > 0) && (
67
- <>
68
- <svg
69
- id="cdc-visualization__paired-bar-chart"
70
- width={width}
71
- height={height}>
72
- <Group top={0} left={config.xAxis.size}>
73
- {data.filter(item => config.series[0].dataKey === groupOne.dataKey).map(d => {
74
- let barWidth = (xScale(d[config.series[0].dataKey]))
75
- return (
76
- <Group key={`group-${groupOne.dataKey}-${d[config.xAxis.dataKey]}`}>
77
- <Bar
78
- className="bar"
79
- key={`bar-${groupOne.dataKey}-${d[config.dataDescription.xKey]}`}
80
- x={halfWidth - barWidth}
81
- y={yScale([d[config.dataDescription.xKey]])}
82
- width={xScale(d[config.series[0].dataKey])}
83
- height={yScale.bandwidth()}
84
- fill={groupOne.color}
85
- data-tip={
86
- `<p>
87
- ${config.dataDescription.seriesKey}: ${groupOne.dataKey}<br/>
88
- ${config.xAxis.dataKey}: ${d[config.xAxis.dataKey]}<br/>
89
- ${config.dataDescription.valueKey}: ${d[groupOne.dataKey]}
90
- </p>`
16
+ const { config, colorScale, transformedData, formatNumber, seriesHighlight } = useContext<any>(Context)
17
+
18
+ if (!config || config?.series?.length < 2) return
19
+
20
+ const data = transformedData
21
+ const adjustedWidth = width
22
+ const adjustedHeight = height
23
+ const halfWidth = adjustedWidth / 2
24
+
25
+ const groupOne = {
26
+ parentKey: config.dataDescription.seriesKey,
27
+ dataKey: config.series[0].dataKey,
28
+ color: colorScale(config.runtime.seriesLabels[config.series[0].dataKey]),
29
+ max: Math.max.apply(
30
+ Math,
31
+ data.map(item => item[config.series[0].dataKey])
32
+ ),
33
+ labelColor: ''
34
+ }
35
+
36
+ const groupTwo = {
37
+ parentKey: config.dataDescription.seriesKey,
38
+ dataKey: config.series[1].dataKey,
39
+ color: colorScale(config.runtime.seriesLabels[config.series[1].dataKey]),
40
+ max: Math.max.apply(
41
+ Math,
42
+ data.map(item => item[config.series[1].dataKey])
43
+ ),
44
+ labelColor: ''
45
+ }
46
+
47
+ const xScale = scaleLinear({
48
+ domain: [0, Math.max(groupOne.max, groupTwo.max)],
49
+ range: [0, halfWidth]
50
+ })
51
+
52
+ const yScale = scaleBand({
53
+ range: [0, adjustedHeight],
54
+ domain: data.map(d => d[config.dataDescription.xKey])
55
+ })
56
+
57
+ // Set label color
58
+ let labelColor = '#000000'
59
+
60
+ if (chroma.contrast(labelColor, groupOne.color) < 4.9) {
61
+ groupOne.labelColor = '#FFFFFF'
62
+ }
63
+
64
+ if (chroma.contrast(labelColor, groupTwo.color) < 4.9) {
65
+ groupTwo.labelColor = '#FFFFFF'
66
+ }
67
+
68
+ const dataTipOne = d => {
69
+ return `<p>
70
+ ${config.dataDescription.seriesKey}: ${groupOne.dataKey}<br/>
71
+ ${config.xAxis.dataKey}: ${d[config.xAxis.dataKey]}<br/>
72
+ ${config.dataDescription.valueKey}: ${formatNumber(d[groupOne.dataKey])}
73
+ </p>`
74
+ }
75
+
76
+ const dataTipTwo = d => {
77
+ return `<p>
78
+ ${config.dataDescription.seriesKey}: ${groupTwo.dataKey}<br/>
79
+ ${config.xAxis.dataKey}: ${d[config.xAxis.dataKey]}<br/>
80
+ ${config.dataDescription.valueKey}: ${formatNumber(d[groupTwo.dataKey])}
81
+ </p>`
82
+ }
83
+
84
+ const isLabelBelowBar = config.yAxis.labelPlacement === 'Below Bar'
85
+ const isLabelOnYAxis = config.yAxis.labelPlacement === 'On Date/Category Axis'
86
+ const isLabelMissing = !config.yAxis.labelPlacement
87
+
88
+ return (
89
+ width > 0 && (
90
+ <>
91
+ <style>
92
+ {`
93
+ #cdc-visualization__paired-bar-chart,
94
+ #cdc-visualization__paired-bar-chart > .visx-group {
95
+ transform-origin: center
96
+ }
97
+ `}
98
+ </style>
99
+ <svg id='cdc-visualization__paired-bar-chart' width={width} height={height} viewBox={`0 0 ${width} ${height}`} role='img' tabIndex={0}>
100
+ <Group top={0} left={config.xAxis.size}>
101
+ {data
102
+ .filter(item => config.series[0].dataKey === groupOne.dataKey)
103
+ .map((d, index) => {
104
+ let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(config.series[0].dataKey) === -1
105
+ let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(config.series[0].dataKey) !== -1
106
+ let barWidth = xScale(d[config.series[0].dataKey])
107
+ let barHeight = Number(config.barHeight) ? Number(config.barHeight) : 25
108
+ let barPadding = barHeight
109
+ config.barHeight = Number(config.barHeight) ? Number(config.barHeight) : 25
110
+ config.barPadding = config.barHeight
111
+
112
+ if (config.orientation === 'horizontal') {
113
+ if (isLabelBelowBar || isLabelMissing || isLabelOnYAxis) {
114
+ if (barHeight < 40) {
115
+ config.barPadding = 40
116
+ } else {
117
+ config.barPadding = barPadding
118
+ }
119
+ } else {
120
+ config.barPadding = barPadding / 2
121
+ }
122
+ }
123
+
124
+ config.height = Number(barHeight) * data.length + config.barPadding * data.length
125
+
126
+ let y = yScale([d[config.dataDescription.xKey]]) + config.barHeight / 1.5
127
+ y = Number(config.barPadding) > 20 ? (y += Number(config.barPadding / 3.5) - config.barHeight / 2) : (y += 0)
128
+
129
+ return (
130
+ <>
131
+ <Group key={`group-${groupOne.dataKey}-${d[config.xAxis.dataKey]}`} className='horizontal'>
132
+ <Bar
133
+ id={`bar-${groupOne.dataKey}-${d[config.dataDescription.xKey]}`}
134
+ className='bar group-1'
135
+ key={`bar-${groupOne.dataKey}-${d[config.dataDescription.xKey]}`}
136
+ x={halfWidth - barWidth}
137
+ y={y}
138
+ width={xScale(d[config.series[0].dataKey])}
139
+ height={barHeight}
140
+ fill={groupOne.color}
141
+ data-tip={dataTipOne(d)}
142
+ data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
143
+ stroke='#333'
144
+ strokeWidth={config.barBorderThickness || 1}
145
+ opacity={transparentBar ? 0.5 : 1}
146
+ display={displayBar ? 'block' : 'none'}
147
+ />
148
+ {config.yAxis.displayNumbersOnBar && displayBar && (
149
+ <Text textAnchor={barWidth < 100 ? 'end' : 'start'} verticalAnchor='middle' x={halfWidth - (barWidth < 100 ? barWidth + 10 : barWidth - 5)} y={y + config.barHeight / 2} fill={barWidth > 100 ? groupOne.labelColor : '#000'}>
150
+ {formatNumber(d[groupOne.dataKey])}
151
+ </Text>
152
+ )}
153
+ </Group>
154
+ </>
155
+ )
156
+ })}
157
+ {data
158
+ .filter(item => config.series[1].dataKey === groupTwo.dataKey)
159
+ .map(d => {
160
+ let barWidth = xScale(d[config.series[1].dataKey])
161
+ let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(config.series[1].dataKey) === -1
162
+ let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(config.series[1].dataKey) !== -1
163
+
164
+ let barHeight = config.barHeight ? config.barHeight : 25
165
+ let barPadding = barHeight
166
+ config.barHeight = Number(config.barHeight)
167
+
168
+ let y = yScale([d[config.dataDescription.xKey]]) + config.barHeight / 1.5
169
+ y = Number(config.barPadding) > 20 ? (y += Number(config.barPadding / 3.5) - config.barHeight / 2) : (y += 0)
170
+
171
+ if (config.orientation === 'horizontal') {
172
+ if (isLabelBelowBar || isLabelMissing || isLabelOnYAxis) {
173
+ if (barHeight < 40) {
174
+ config.barPadding = 40
175
+ } else {
176
+ config.barPadding = barPadding
177
+ }
178
+ } else {
179
+ config.barPadding = barPadding / 2
180
+ }
181
+ }
182
+
183
+ return (
184
+ <>
185
+ <style>
186
+ {`
187
+ .bar-${groupTwo.dataKey}-${d[config.xAxis.dataKey]} {
188
+ transform-origin: ${halfWidth}px ${y}px
91
189
  }
92
- data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
93
- />
94
- <Text
95
- textAnchor={barWidth < 100 ? 'end' : 'start' }
96
- x={halfWidth - (barWidth < 100 ? barWidth + 10 : barWidth - 5)}
97
- y={yScale([d[config.dataDescription.xKey]]) + yScale.bandwidth() / 1.5}
98
- fill={barWidth > 100 ? groupOne.labelColor : '#000' }>
99
- {d[config.dataDescription.xKey]}
100
- </Text>
101
- </Group>
102
- )}
103
- )}
104
- {data.filter(item => config.series[1].dataKey === groupTwo.dataKey).map(d => {
105
- let barWidth = (xScale(d[config.series[1].dataKey]))
106
-
107
- return(
108
- <Group key={`group-${groupTwo.dataKey}-${d[config.dataDescription.xKey]}`}>
109
- <Bar
110
- className="bar"
111
- key={`bar-${groupTwo.dataKey}-${d[config.dataDescription.xKey]}`}
112
- x={halfWidth}
113
- y={yScale([d[config.dataDescription.xKey]])}
114
- width={xScale(d[config.series[1].dataKey])}
115
- height={yScale.bandwidth()}
116
- fill={groupTwo.color}
117
- data-tip={
118
- `<p>
119
- ${config.dataDescription.seriesKey}: ${groupTwo.dataKey}<br/>
120
- ${config.xAxis.dataKey}: ${d[config.xAxis.dataKey]}<br/>
121
- ${config.dataDescription.valueKey}: ${d[groupTwo.dataKey]}
122
- </p>`
123
- }
124
- data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
125
-
126
- />
127
- <Text
128
- textAnchor={barWidth < 100 ? 'start' : 'end' }
129
- x={halfWidth + (barWidth < 100 ? barWidth + 10 : barWidth - 10 )}
130
- y={yScale([d[config.dataDescription.xKey]]) + (yScale.bandwidth() / 1.5)}
131
- fill={barWidth > 100 ? groupTwo.labelColor : '#000' }>
132
- {d[config.dataDescription.xKey]}
133
- </Text>
134
- </Group>
135
- )
136
- }
137
- )}
138
- </Group>
139
- </svg>
140
- </>
141
- );
190
+ `}
191
+ </style>
192
+ <Group key={`group-${groupTwo.dataKey}-${d[config.dataDescription.xKey]}`} className='horizontal'>
193
+ <Bar
194
+ id={`bar-${groupTwo.dataKey}-${d[config.dataDescription.xKey]}`}
195
+ className='bar group-2'
196
+ key={`bar-${groupTwo.dataKey}-${d[config.dataDescription.xKey]}`}
197
+ x={halfWidth}
198
+ y={y}
199
+ width={xScale(d[config.series[1].dataKey])}
200
+ height={barHeight}
201
+ fill={groupTwo.color}
202
+ data-tip={dataTipTwo(d)}
203
+ data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
204
+ strokeWidth={config.barBorderThickness || 1}
205
+ stroke='#333'
206
+ opacity={transparentBar ? 0.5 : 1}
207
+ display={displayBar ? 'block' : 'none'}
208
+ />
209
+ {config.yAxis.displayNumbersOnBar && displayBar && (
210
+ <Text textAnchor={barWidth < 100 ? 'start' : 'end'} verticalAnchor='middle' x={halfWidth + (barWidth < 100 ? barWidth + 10 : barWidth - 10)} y={y + config.barHeight / 2} fill={barWidth > 100 ? groupTwo.labelColor : '#000'}>
211
+ {formatNumber(d[groupTwo.dataKey])}
212
+ </Text>
213
+ )}
214
+ </Group>
215
+ </>
216
+ )
217
+ })}
218
+ </Group>
219
+ </svg>
220
+ </>
221
+ )
222
+ )
142
223
  }
143
224
 
144
- export default PairedBarChart;
225
+ export default PairedBarChart
@@ -1,42 +1,51 @@
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';
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'
9
10
 
10
- import Context from '../context';
11
+ import Context from '../context'
11
12
 
12
- import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
13
+ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
13
14
 
14
15
  // react-spring transition definitions
15
- type PieStyles = { startAngle: number; endAngle: number };
16
+ type PieStyles = { startAngle: number; endAngle: number }
16
17
 
17
18
  const enterUpdateTransition = ({ startAngle, endAngle }: PieArcDatum<any>) => ({
18
19
  startAngle,
19
- endAngle,
20
- });
20
+ endAngle
21
+ })
21
22
 
22
23
  export default function PieChart() {
23
- const { transformedData: data, config, dimensions, seriesHighlight, colorScale, formatNumber, currentViewport } = useContext<any>(Context);
24
+ const { transformedData: data, config, dimensions, seriesHighlight, colorScale, formatNumber, currentViewport, handleChartAriaLabels } = useContext<any>(Context)
24
25
 
25
- const [filteredData, setFilteredData] = useState<any>(undefined);
26
+ const [filteredData, setFilteredData] = useState<any>(undefined)
27
+ const [animatedPie, setAnimatePie] = useState<boolean>(false)
26
28
 
27
-
29
+ const triggerRef = useRef()
30
+ const dataRef = useIntersectionObserver(triggerRef, {
31
+ freezeOnceVisible: false
32
+ })
33
+
34
+ useEffect(() => {
35
+ if (dataRef?.isIntersecting && config.animate && !animatedPie) {
36
+ setTimeout(() => {
37
+ setAnimatePie(true)
38
+ }, 500)
39
+ }
40
+ }, [dataRef?.isIntersecting, config.animate])
28
41
 
29
42
  type AnimatedPieProps<Datum> = ProvidedProps<Datum> & {
30
- animate?: boolean;
31
- getKey: (d: PieArcDatum<Datum>) => string;
32
- delay?: number;
33
- };
34
-
35
- function AnimatedPie<Datum>({
36
- arcs,
37
- path,
38
- getKey,
39
- }: AnimatedPieProps<Datum>) {
43
+ animate?: boolean
44
+ getKey: (d: PieArcDatum<Datum>) => string
45
+ delay?: number
46
+ }
47
+
48
+ function AnimatedPie<Datum>({ arcs, path, getKey }: AnimatedPieProps<Datum>) {
40
49
  const transitions = useTransition<PieArcDatum<Datum>, PieStyles>(
41
50
  arcs,
42
51
  getKey,
@@ -45,145 +54,107 @@ export default function PieChart() {
45
54
  from: enterUpdateTransition,
46
55
  enter: enterUpdateTransition,
47
56
  update: enterUpdateTransition,
48
- leave: enterUpdateTransition,
49
- },
50
- );
57
+ leave: enterUpdateTransition
58
+ }
59
+ )
51
60
 
52
61
  return (
53
62
  <>
54
- {transitions.map(
55
- ({
56
- item: arc,
57
- props,
58
- key,
59
- }: {
60
- item: PieArcDatum<Datum>;
61
- props: PieStyles;
62
- key: string;
63
- }) => {
64
- let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${formatNumber(arc.data[config.runtime.yAxis.dataKey])}` : formatNumber(arc.data[config.runtime.yAxis.dataKey])
65
- let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${arc.data[config.runtime.xAxis.dataKey]}` : arc.data[config.runtime.xAxis.dataKey]
66
-
67
- const tooltip = `<div>
68
- ${yAxisTooltip}<br />
69
- ${xAxisTooltip}<br />`
63
+ {transitions.map(({ item: arc, props, key }: { item: PieArcDatum<Datum>; props: PieStyles; key: string }) => {
64
+ let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${formatNumber(arc.data[config.runtime.yAxis.dataKey])}` : formatNumber(arc.data[config.runtime.yAxis.dataKey])
65
+ let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${arc.data[config.runtime.xAxis.dataKey]}` : arc.data[config.runtime.xAxis.dataKey]
70
66
 
71
- return (
72
- <Group key={key} style={{ opacity: (config.legend.behavior === "highlight" && seriesHighlight.length > 0 && seriesHighlight.indexOf(arc.data[config.runtime.xAxis.dataKey]) === -1) ? 0.5 : 1 }}>
73
- <animated.path
74
- // compute interpolated path d attribute from intermediate angle values
75
- d={interpolate([props.startAngle, props.endAngle], (startAngle, endAngle) => path({
67
+ const tooltip = `<div>
68
+ ${yAxisTooltip}<br />
69
+ ${xAxisTooltip}<br />
70
+ Percent: ${Math.round((((arc.endAngle - arc.startAngle) * 180) / Math.PI / 360) * 100) + '%'}
71
+ `
72
+
73
+ return (
74
+ <Group key={key} style={{ opacity: config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(arc.data[config.runtime.xAxis.dataKey]) === -1 ? 0.5 : 1 }}>
75
+ <animated.path
76
+ // compute interpolated path d attribute from intermediate angle values
77
+ d={interpolate([props.startAngle, props.endAngle], (startAngle, endAngle) =>
78
+ path({
76
79
  ...arc,
77
80
  startAngle,
78
- endAngle,
79
- }))}
80
- fill={colorScale(arc.data[config.runtime.xAxis.dataKey])}
81
- data-tip={tooltip}
82
- data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
83
- />
84
- </Group>
85
- );
86
- },
87
- )}
88
- {transitions.map(
89
- ({
90
- item: arc,
91
- key,
92
- }: {
93
- item: PieArcDatum<Datum>;
94
- props: PieStyles;
95
- key: string;
96
- }) => {
97
-
98
- const [centroidX, centroidY] = path.centroid(arc);
99
- const hasSpaceForLabel = arc.endAngle - arc.startAngle >= 0.1;
100
-
101
- let textColor = "#FFF";
102
- if (chroma.contrast(textColor, colorScale(arc.data[config.runtime.xAxis.dataKey])) < 3.5) {
103
- textColor = "000";
104
- }
105
-
106
- return (
107
- <animated.g key={key}>
108
- {hasSpaceForLabel && (
109
- <Text
110
- style={{ fill: textColor }}
111
- x={centroidX}
112
- y={centroidY}
113
- dy=".33em"
114
- textAnchor="middle"
115
- pointerEvents="none"
116
- >
117
- {Math.round(
118
- (((arc.endAngle - arc.startAngle) * 180) /
119
- Math.PI /
120
- 360) *
121
- 100
122
- ) + "%"}
123
- </Text>
81
+ endAngle
82
+ })
124
83
  )}
125
- </animated.g>
126
- );
127
- },
128
- )}
84
+ fill={colorScale(arc.data[config.runtime.xAxis.dataKey])}
85
+ data-tip={tooltip}
86
+ data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
87
+ />
88
+ </Group>
89
+ )
90
+ })}
91
+ {transitions.map(({ item: arc, key }: { item: PieArcDatum<Datum>; props: PieStyles; key: string }) => {
92
+ const [centroidX, centroidY] = path.centroid(arc)
93
+ const hasSpaceForLabel = arc.endAngle - arc.startAngle >= 0.1
94
+
95
+ let textColor = '#FFF'
96
+ if (colorScale(arc.data[config.runtime.xAxis.dataKey]) && chroma.contrast(textColor, colorScale(arc.data[config.runtime.xAxis.dataKey])) < 3.5) {
97
+ textColor = '000'
98
+ }
99
+
100
+ return (
101
+ <animated.g key={key}>
102
+ {hasSpaceForLabel && (
103
+ <Text style={{ fill: textColor }} x={centroidX} y={centroidY} dy='.33em' textAnchor='middle' pointerEvents='none'>
104
+ {Math.round((((arc.endAngle - arc.startAngle) * 180) / Math.PI / 360) * 100) + '%'}
105
+ </Text>
106
+ )}
107
+ </animated.g>
108
+ )
109
+ })}
129
110
  </>
130
- );
111
+ )
131
112
  }
132
113
 
133
- let [ width ] = dimensions;
114
+ let [width] = dimensions
134
115
 
135
- if(config && config.legend && !config.legend.hide && currentViewport === 'lg') {
136
- width = width * 0.73;
116
+ if (config && config.legend && !config.legend.hide && currentViewport === 'lg') {
117
+ width = width * 0.73
137
118
  }
138
119
 
139
- const height = config.aspectRatio ? (width * config.aspectRatio) : config.height;
120
+ const height = config.aspectRatio ? width * config.aspectRatio : config.height
140
121
 
141
- const radius = Math.min(width, height) / 2;
142
- const centerY = height / 2;
143
- const centerX = width / 2;
144
- const donutThickness = (config.pieType === "Donut") ? 75 : radius;
122
+ const radius = Math.min(width, height) / 2
123
+ const centerY = height / 2
124
+ const centerX = width / 2
125
+ const donutThickness = config.pieType === 'Donut' ? 75 : radius
145
126
 
146
127
  useEffect(() => {
147
- if(seriesHighlight.length > 0 && config.legend.behavior !== "highlight"){
148
- let newFilteredData = [];
128
+ if (seriesHighlight.length > 0 && config.legend.behavior !== 'highlight') {
129
+ let newFilteredData = []
149
130
 
150
- data.forEach((d) => {
151
- if(seriesHighlight.indexOf(d[config.runtime.xAxis.dataKey]) !== -1) {
152
- newFilteredData.push(d);
131
+ data.forEach(d => {
132
+ if (seriesHighlight.indexOf(d[config.runtime.xAxis.dataKey]) !== -1) {
133
+ newFilteredData.push(d)
153
134
  }
154
- });
135
+ })
155
136
 
156
- setFilteredData(newFilteredData);
137
+ setFilteredData(newFilteredData)
157
138
  } else {
158
- setFilteredData(undefined);
139
+ setFilteredData(undefined)
159
140
  }
160
- }, [seriesHighlight]);
141
+ }, [seriesHighlight])
161
142
 
162
143
  useEffect(() => {
163
- ReactTooltip.rebuild();
164
- });
144
+ ReactTooltip.rebuild()
145
+ })
165
146
 
166
147
  return (
167
- <ErrorBoundary component="PieChart">
168
- <svg width={width} height={height}>
148
+ <ErrorBoundary component='PieChart'>
149
+ <svg width={width} height={height} className={`group ${animatedPie ? 'animated' : ''}`} role='img' aria-label={handleChartAriaLabels(config)}>
169
150
  <Group top={centerY} left={centerX}>
170
- <Pie
171
- data={filteredData || data}
172
- pieValue={d => d[config.runtime.yAxis.dataKey]}
173
- pieSortValues={() => -1}
174
- innerRadius={radius - donutThickness}
175
- outerRadius={radius}
176
- >
177
- {pie => (
178
- <AnimatedPie<any>
179
- {...pie}
180
- getKey={d => d.data[config.runtime.xAxis.dataKey]}
181
- />
182
- )}
151
+ <Pie data={filteredData || data} pieValue={d => d[config.runtime.yAxis.dataKey]} pieSortValues={() => -1} innerRadius={radius - donutThickness} outerRadius={radius}>
152
+ {pie => <AnimatedPie<any> {...pie} getKey={d => d.data[config.runtime.xAxis.dataKey]} />}
183
153
  </Pie>
184
154
  </Group>
185
155
  </svg>
186
- <ReactTooltip id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} html={true} type="light" arrowColor="rgba(0,0,0,0)" className="tooltip"/>
156
+ <div ref={triggerRef} />
157
+ <ReactTooltip id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} html={true} type='light' arrowColor='rgba(0,0,0,0)' className='tooltip' />
187
158
  </ErrorBoundary>
188
159
  )
189
160
  }