@cdc/chart 4.22.10 → 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.
- package/README.md +5 -5
- package/dist/cdcchart.js +4 -4
- package/examples/age-adjusted-rates.json +1486 -1218
- 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 +136 -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 +110 -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/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/private/filters.json +170 -0
- package/examples/private/line-test-data.json +21 -21
- package/examples/private/line-test-two.json +209 -215
- package/examples/private/line-test.json +101 -101
- package/examples/private/new.json +48800 -0
- package/examples/private/shawn.json +1105 -1295
- package/examples/private/test.json +10123 -10123
- package/examples/private/yaxis-test.json +4 -3
- package/examples/private/yaxis.json +26 -26
- 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 +2 -2
- package/src/CdcChart.tsx +339 -380
- package/src/components/BarChart.tsx +425 -469
- package/src/components/DataTable.tsx +164 -195
- package/src/components/EditorPanel.js +1009 -710
- package/src/components/Legend.js +279 -329
- package/src/components/LineChart.tsx +90 -79
- package/src/components/LinearChart.tsx +376 -434
- package/src/components/PairedBarChart.tsx +197 -213
- package/src/components/PieChart.tsx +95 -151
- package/src/components/SparkLine.js +179 -201
- package/src/components/useIntersectionObserver.tsx +17 -20
- package/src/context.tsx +3 -3
- package/src/data/initial-state.js +37 -16
- 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 +62 -78
- package/src/hooks/useRightAxis.js +25 -0
- package/src/hooks/useTopAxis.js +6 -0
- package/src/index.html +45 -45
- package/src/index.tsx +13 -16
- package/src/scss/DataTable.scss +5 -4
- package/src/scss/editor-panel.scss +71 -69
- package/src/scss/main.scss +157 -114
- package/src/scss/variables.scss +1 -1
|
@@ -1,55 +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
|
|
7
|
-
import { Group } from '@visx/group'
|
|
8
|
-
import { Text } from '@visx/text'
|
|
9
|
-
import useIntersectionObserver from
|
|
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
|
+
useEffect(() => {
|
|
35
35
|
if (dataRef?.isIntersecting && config.animate && !animatedPie) {
|
|
36
36
|
setTimeout(() => {
|
|
37
|
-
setAnimatePie(true)
|
|
38
|
-
}, 500)
|
|
37
|
+
setAnimatePie(true)
|
|
38
|
+
}, 500)
|
|
39
39
|
}
|
|
40
40
|
}, [dataRef?.isIntersecting, config.animate])
|
|
41
41
|
|
|
42
42
|
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>) {
|
|
43
|
+
animate?: boolean
|
|
44
|
+
getKey: (d: PieArcDatum<Datum>) => string
|
|
45
|
+
delay?: number
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function AnimatedPie<Datum>({ arcs, path, getKey }: AnimatedPieProps<Datum>) {
|
|
53
49
|
const transitions = useTransition<PieArcDatum<Datum>, PieStyles>(
|
|
54
50
|
arcs,
|
|
55
51
|
getKey,
|
|
@@ -58,159 +54,107 @@ export default function PieChart() {
|
|
|
58
54
|
from: enterUpdateTransition,
|
|
59
55
|
enter: enterUpdateTransition,
|
|
60
56
|
update: enterUpdateTransition,
|
|
61
|
-
leave: enterUpdateTransition
|
|
62
|
-
}
|
|
63
|
-
)
|
|
57
|
+
leave: enterUpdateTransition
|
|
58
|
+
}
|
|
59
|
+
)
|
|
64
60
|
|
|
65
61
|
return (
|
|
66
62
|
<>
|
|
67
|
-
{transitions.map(
|
|
68
|
-
(
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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>
|
|
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]
|
|
66
|
+
|
|
67
|
+
const tooltip = `<div>
|
|
81
68
|
${yAxisTooltip}<br />
|
|
82
69
|
${xAxisTooltip}<br />
|
|
83
|
-
Percent: ${Math.round(
|
|
84
|
-
(((arc.endAngle - arc.startAngle) * 180) /
|
|
85
|
-
Math.PI /
|
|
86
|
-
360) *
|
|
87
|
-
100
|
|
88
|
-
) + "%"}
|
|
70
|
+
Percent: ${Math.round((((arc.endAngle - arc.startAngle) * 180) / Math.PI / 360) * 100) + '%'}
|
|
89
71
|
`
|
|
90
72
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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({
|
|
96
79
|
...arc,
|
|
97
80
|
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>
|
|
81
|
+
endAngle
|
|
82
|
+
})
|
|
144
83
|
)}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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
|
+
})}
|
|
149
110
|
</>
|
|
150
|
-
)
|
|
111
|
+
)
|
|
151
112
|
}
|
|
152
113
|
|
|
153
|
-
let [
|
|
114
|
+
let [width] = dimensions
|
|
154
115
|
|
|
155
|
-
if(config && config.legend && !config.legend.hide && currentViewport === 'lg') {
|
|
156
|
-
width = width * 0.73
|
|
116
|
+
if (config && config.legend && !config.legend.hide && currentViewport === 'lg') {
|
|
117
|
+
width = width * 0.73
|
|
157
118
|
}
|
|
158
119
|
|
|
159
|
-
const height = config.aspectRatio ?
|
|
120
|
+
const height = config.aspectRatio ? width * config.aspectRatio : config.height
|
|
160
121
|
|
|
161
|
-
const radius = Math.min(width, height) / 2
|
|
162
|
-
const centerY = height / 2
|
|
163
|
-
const centerX = width / 2
|
|
164
|
-
const donutThickness =
|
|
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
|
|
165
126
|
|
|
166
127
|
useEffect(() => {
|
|
167
|
-
if(seriesHighlight.length > 0 && config.legend.behavior !==
|
|
168
|
-
let newFilteredData = []
|
|
128
|
+
if (seriesHighlight.length > 0 && config.legend.behavior !== 'highlight') {
|
|
129
|
+
let newFilteredData = []
|
|
169
130
|
|
|
170
|
-
data.forEach(
|
|
171
|
-
if(seriesHighlight.indexOf(d[config.runtime.xAxis.dataKey]) !== -1) {
|
|
172
|
-
newFilteredData.push(d)
|
|
131
|
+
data.forEach(d => {
|
|
132
|
+
if (seriesHighlight.indexOf(d[config.runtime.xAxis.dataKey]) !== -1) {
|
|
133
|
+
newFilteredData.push(d)
|
|
173
134
|
}
|
|
174
|
-
})
|
|
135
|
+
})
|
|
175
136
|
|
|
176
|
-
setFilteredData(newFilteredData)
|
|
137
|
+
setFilteredData(newFilteredData)
|
|
177
138
|
} else {
|
|
178
|
-
setFilteredData(undefined)
|
|
139
|
+
setFilteredData(undefined)
|
|
179
140
|
}
|
|
180
|
-
}, [seriesHighlight])
|
|
141
|
+
}, [seriesHighlight])
|
|
181
142
|
|
|
182
143
|
useEffect(() => {
|
|
183
|
-
ReactTooltip.rebuild()
|
|
184
|
-
})
|
|
144
|
+
ReactTooltip.rebuild()
|
|
145
|
+
})
|
|
185
146
|
|
|
186
147
|
return (
|
|
187
|
-
<ErrorBoundary component=
|
|
188
|
-
<svg
|
|
189
|
-
width={width}
|
|
190
|
-
height={height}
|
|
191
|
-
className={`group ${animatedPie ? 'animated' : ''}`}
|
|
192
|
-
role="img"
|
|
193
|
-
aria-label={handleChartAriaLabels(config)}
|
|
194
|
-
>
|
|
148
|
+
<ErrorBoundary component='PieChart'>
|
|
149
|
+
<svg width={width} height={height} className={`group ${animatedPie ? 'animated' : ''}`} role='img' aria-label={handleChartAriaLabels(config)}>
|
|
195
150
|
<Group top={centerY} left={centerX}>
|
|
196
|
-
<Pie
|
|
197
|
-
|
|
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
|
-
)}
|
|
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]} />}
|
|
209
153
|
</Pie>
|
|
210
154
|
</Group>
|
|
211
155
|
</svg>
|
|
212
156
|
<div ref={triggerRef} />
|
|
213
|
-
<ReactTooltip id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} html={true} type=
|
|
157
|
+
<ReactTooltip id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} html={true} type='light' arrowColor='rgba(0,0,0,0)' className='tooltip' />
|
|
214
158
|
</ErrorBoundary>
|
|
215
159
|
)
|
|
216
160
|
}
|