@cdc/chart 4.24.2 → 4.24.3
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 +47386 -36618
- package/examples/chart-regression-1.json +378 -0
- package/examples/chart-regression-2.json +2360 -0
- package/examples/feature/filters/url-filter.json +1076 -0
- package/examples/feature/line/line-chart.json +2 -1
- package/examples/feature/regions/index.json +50 -4
- package/examples/feature/sankey/sankey-example-data.json +1364 -0
- package/examples/feature/sankey/sankey_chart_data.csv +20 -0
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +306 -19
- package/examples/sparkline.json +868 -0
- package/index.html +128 -123
- package/package.json +4 -2
- package/src/CdcChart.tsx +40 -22
- package/src/_stories/ChartEditor.stories.tsx +14 -3
- package/src/_stories/_mock/url_filter.json +1076 -0
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +2 -1
- package/src/components/AreaChart/components/AreaChart.jsx +2 -1
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +39 -49
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +36 -56
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +32 -39
- package/src/components/BarChart/components/BarChart.Vertical.tsx +40 -55
- package/src/components/BoxPlot/BoxPlot.jsx +2 -1
- package/src/components/DeviationBar.jsx +3 -3
- package/src/components/EditorPanel/EditorPanel.tsx +167 -15
- package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +1 -1
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +108 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +48 -4
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +41 -0
- package/src/components/EditorPanel/components/Panels/index.tsx +9 -7
- package/src/components/EditorPanel/components/panels.scss +11 -0
- package/src/components/EditorPanel/useEditorPermissions.js +40 -14
- package/src/components/Legend/Legend.Component.tsx +23 -15
- package/src/components/Legend/Legend.tsx +4 -4
- package/src/components/LineChart/LineChartProps.ts +1 -0
- package/src/components/LineChart/helpers.ts +2 -2
- package/src/components/LineChart/index.tsx +7 -7
- package/src/components/LinearChart.jsx +9 -30
- package/src/components/PairedBarChart.jsx +6 -10
- package/src/components/PieChart/PieChart.tsx +3 -3
- package/src/components/Regions/components/Regions.tsx +120 -78
- package/src/components/Sankey/index.tsx +434 -0
- package/src/components/Sankey/sankey.scss +153 -0
- package/src/components/Sankey/types/index.ts +16 -0
- package/src/components/ScatterPlot/ScatterPlot.jsx +1 -0
- package/src/components/Sparkline/{SparkLine.jsx → components/SparkLine.tsx} +14 -30
- package/src/components/Sparkline/index.scss +3 -0
- package/src/components/Sparkline/index.tsx +1 -1
- package/src/components/ZoomBrush.tsx +2 -1
- package/src/data/initial-state.js +46 -2
- package/src/helpers/computeMarginBottom.ts +2 -1
- package/src/helpers/tests/computeMarginBottom.test.ts +2 -1
- package/src/hooks/useBarChart.js +5 -2
- package/src/hooks/useScales.ts +15 -18
- package/src/hooks/useTooltip.tsx +9 -8
- package/src/scss/main.scss +8 -29
- package/src/types/ChartConfig.ts +32 -14
- package/src/types/ChartContext.ts +7 -0
|
@@ -3,6 +3,7 @@ import React, { useContext, memo } from 'react'
|
|
|
3
3
|
// cdc
|
|
4
4
|
import ConfigContext from '../../../ConfigContext'
|
|
5
5
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
6
|
+
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
6
7
|
|
|
7
8
|
// visx & d3
|
|
8
9
|
import * as allCurves from '@visx/curve'
|
|
@@ -20,7 +21,7 @@ const AreaChartStacked = ({ xScale, yScale, yMax, xMax, handleTooltipMouseOver,
|
|
|
20
21
|
|
|
21
22
|
const handleDateCategory = value => {
|
|
22
23
|
if (config.xAxis.type === 'categorical') return xScale(value)
|
|
23
|
-
if (config.xAxis
|
|
24
|
+
if (isDateScale(config.xAxis)) {
|
|
24
25
|
let date = new Date(value)
|
|
25
26
|
return xScale(date)
|
|
26
27
|
}
|
|
@@ -3,6 +3,7 @@ import React, { useContext, memo } from 'react'
|
|
|
3
3
|
// cdc
|
|
4
4
|
import ConfigContext from '../../../ConfigContext'
|
|
5
5
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
6
|
+
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
6
7
|
|
|
7
8
|
// visx & d3
|
|
8
9
|
import * as allCurves from '@visx/curve'
|
|
@@ -19,7 +20,7 @@ const AreaChart = props => {
|
|
|
19
20
|
if (!data) return
|
|
20
21
|
|
|
21
22
|
const handleX = d => {
|
|
22
|
-
return (config.xAxis
|
|
23
|
+
return (isDateScale(config.xAxis) ? xScale(parseDate(d[config.xAxis.dataKey], false)) : xScale(d[config.xAxis.dataKey])) + (xScale.bandwidth ? xScale.bandwidth() / 2 : 0)
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
const handleY = (d, index, s = undefined) => {
|
|
@@ -6,19 +6,21 @@ import { Text } from '@visx/text'
|
|
|
6
6
|
import { BarGroup } from '@visx/shape'
|
|
7
7
|
import { useHighlightedBars } from '../../../hooks/useHighlightedBars'
|
|
8
8
|
import { FaStar } from 'react-icons/fa'
|
|
9
|
+
import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
|
|
9
10
|
|
|
10
11
|
// third party
|
|
11
12
|
import chroma from 'chroma-js'
|
|
12
13
|
import BarChartContext, { BarChartContextValues } from './context'
|
|
13
14
|
import { ChartContext } from '../../../types/ChartContext'
|
|
14
15
|
|
|
16
|
+
import createBarElement from '@cdc/core/components/createBarElement'
|
|
17
|
+
|
|
15
18
|
export const BarChartHorizontal = () => {
|
|
16
19
|
const { xScale, yScale, yMax, seriesScale } = useContext<BarChartContextValues>(BarChartContext)
|
|
17
20
|
const { transformedData: data, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, setSharedFilter, isNumber, getTextWidth, getYAxisData, getXAxisData } = useContext<ChartContext>(ConfigContext)
|
|
18
21
|
const {
|
|
19
22
|
isHorizontal,
|
|
20
23
|
barBorderWidth,
|
|
21
|
-
applyRadius,
|
|
22
24
|
updateBars,
|
|
23
25
|
assignColorsToValues,
|
|
24
26
|
section,
|
|
@@ -112,7 +114,6 @@ export const BarChartHorizontal = () => {
|
|
|
112
114
|
|
|
113
115
|
// create new Index for bars with negative values
|
|
114
116
|
const newIndex = bar.value < 0 ? -1 : index
|
|
115
|
-
const borderRadius = applyRadius(newIndex)
|
|
116
117
|
|
|
117
118
|
let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${xAxisValue}` : xAxisValue
|
|
118
119
|
const additionalColTooltip = getAdditionalColumn(hoveredBar)
|
|
@@ -137,10 +138,8 @@ export const BarChartHorizontal = () => {
|
|
|
137
138
|
const borderWidth = isHighlightedBar ? highlightedBar.borderWidth : config.isLollipopChart ? 0 : config.barHasBorder === 'true' ? barBorderWidth : 0
|
|
138
139
|
const displaylollipopShape = config.suppressedData.some(d => bar.key === d.column && bar.value === d.value) ? 'none' : 'block'
|
|
139
140
|
// update label color
|
|
140
|
-
if (barColor && labelColor) {
|
|
141
|
-
|
|
142
|
-
labelColor = textFits ? '#FFFFFF' : '#000000'
|
|
143
|
-
}
|
|
141
|
+
if (barColor && labelColor && textFits) {
|
|
142
|
+
labelColor = getContrastColor('#000', barColor)
|
|
144
143
|
}
|
|
145
144
|
const getTop = () => {
|
|
146
145
|
if (Number(barHeight) < 20) return -4
|
|
@@ -154,15 +153,6 @@ export const BarChartHorizontal = () => {
|
|
|
154
153
|
return 12
|
|
155
154
|
}
|
|
156
155
|
}
|
|
157
|
-
const iconStyle: { [key: string]: any } = {
|
|
158
|
-
position: 'absolute',
|
|
159
|
-
top: getTop(),
|
|
160
|
-
left: suppresedBarWidth * 1.2
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (config.isLollipopChart) {
|
|
164
|
-
iconStyle.top = -9
|
|
165
|
-
}
|
|
166
156
|
const background = () => {
|
|
167
157
|
if (isRegularLollipopColor) return barColor
|
|
168
158
|
if (isTwoToneLollipopColor) return chroma(barColor).brighten(1)
|
|
@@ -170,39 +160,42 @@ export const BarChartHorizontal = () => {
|
|
|
170
160
|
return barColor
|
|
171
161
|
}
|
|
172
162
|
|
|
173
|
-
const finalStyle = {
|
|
174
|
-
background: background(),
|
|
175
|
-
borderColor,
|
|
176
|
-
borderStyle: 'solid',
|
|
177
|
-
borderWidth,
|
|
178
|
-
width: barWidth,
|
|
179
|
-
transition: 'all 0.2s linear',
|
|
180
|
-
height: !config.isLollipopChart ? barHeight : lollipopBarWidth,
|
|
181
|
-
...borderRadius
|
|
182
|
-
}
|
|
183
|
-
|
|
184
163
|
return (
|
|
185
164
|
<Group key={`${barGroup.index}--${index}`}>
|
|
186
|
-
{/* This feels gross but inline transition was not working well*/}
|
|
187
|
-
<style>
|
|
188
|
-
{`
|
|
189
|
-
.linear #barGroup${barGroup.index} div,
|
|
190
|
-
.Combo #barGroup${barGroup.index} div {
|
|
191
|
-
transform-origin: 0 ${barY + barHeight}px;
|
|
192
|
-
}
|
|
193
|
-
`}
|
|
194
|
-
</style>
|
|
195
165
|
<Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
|
|
196
|
-
|
|
166
|
+
{createBarElement({
|
|
167
|
+
config: config,
|
|
168
|
+
index: newIndex,
|
|
169
|
+
id: `barGroup${barGroup.index}`,
|
|
170
|
+
background: background(),
|
|
171
|
+
borderColor,
|
|
172
|
+
borderStyle: 'solid',
|
|
173
|
+
borderWidth: `${borderWidth}px`,
|
|
174
|
+
width: barWidth,
|
|
175
|
+
height: !config.isLollipopChart ? barHeight : lollipopBarWidth,
|
|
176
|
+
x: barX,
|
|
177
|
+
y: barHeight * bar.index,
|
|
178
|
+
onMouseOver: () => onMouseOverBar(xAxisValue, bar.key),
|
|
179
|
+
onMouseLeave: onMouseLeaveBar,
|
|
180
|
+
tooltipHtml: tooltip,
|
|
181
|
+
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
182
|
+
onClick: e => {
|
|
183
|
+
e.preventDefault()
|
|
184
|
+
if (setSharedFilter) {
|
|
185
|
+
bar[config.xAxis.dataKey] = yAxisValue
|
|
186
|
+
setSharedFilter(config.uid, bar)
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
styleOverrides: {
|
|
190
|
+
transformOrigin: `0 ${barY + barHeight}px`,
|
|
191
|
+
opacity: transparentBar ? 0.2 : 1,
|
|
192
|
+
display: displayBar ? 'block' : 'none'
|
|
193
|
+
}
|
|
194
|
+
})}
|
|
195
|
+
<g
|
|
196
|
+
transform={`translate(${barX},${barHeight * bar.index})`}
|
|
197
197
|
onMouseOver={() => onMouseOverBar(xAxisValue, bar.key)}
|
|
198
198
|
onMouseLeave={onMouseLeaveBar}
|
|
199
|
-
id={`barGroup${barGroup.index}`}
|
|
200
|
-
key={`bar-group-bar-${barGroup.index}-${bar.index}-${bar.value}-${bar.key}`}
|
|
201
|
-
x={barX}
|
|
202
|
-
style={{ overflow: 'visible', ...finalStyle }}
|
|
203
|
-
y={barHeight * bar.index}
|
|
204
|
-
height={!config.isLollipopChart ? barHeight : lollipopBarWidth}
|
|
205
|
-
width={barWidth}
|
|
206
199
|
opacity={transparentBar ? 0.2 : 1}
|
|
207
200
|
display={displayBar ? 'block' : 'none'}
|
|
208
201
|
data-tooltip-html={tooltip}
|
|
@@ -215,11 +208,8 @@ export const BarChartHorizontal = () => {
|
|
|
215
208
|
}
|
|
216
209
|
}}
|
|
217
210
|
>
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
<div style={{ ...finalStyle }}></div>
|
|
221
|
-
</div>
|
|
222
|
-
</foreignObject>
|
|
211
|
+
{getIcon(bar, barWidth)}
|
|
212
|
+
</g>
|
|
223
213
|
|
|
224
214
|
{!config.isLollipopChart && displayNumbersOnBar && (
|
|
225
215
|
<Text // prettier-ignore
|
|
@@ -262,7 +252,7 @@ export const BarChartHorizontal = () => {
|
|
|
262
252
|
<circle
|
|
263
253
|
display={displaylollipopShape}
|
|
264
254
|
cx={bar.y}
|
|
265
|
-
cy={
|
|
255
|
+
cy={barHeight * bar.index + lollipopBarWidth / 2}
|
|
266
256
|
r={lollipopShapeSize / 2}
|
|
267
257
|
fill={barColor}
|
|
268
258
|
key={`circle--${bar.index}`}
|
|
@@ -4,14 +4,14 @@ import { useBarChart } from '../../../hooks/useBarChart'
|
|
|
4
4
|
import { BarStackHorizontal } from '@visx/shape'
|
|
5
5
|
import { Group } from '@visx/group'
|
|
6
6
|
import { Text } from '@visx/text'
|
|
7
|
-
|
|
8
|
-
// third party
|
|
9
|
-
import chroma from 'chroma-js'
|
|
7
|
+
import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
|
|
10
8
|
|
|
11
9
|
// types
|
|
12
10
|
import BarChartContext, { type BarChartContextValues } from './context'
|
|
13
11
|
import { type ChartContext } from '../../../types/ChartContext'
|
|
14
12
|
|
|
13
|
+
import createBarElement from '@cdc/core/components/createBarElement'
|
|
14
|
+
|
|
15
15
|
const BarChartStackedHorizontal = () => {
|
|
16
16
|
const { yMax, yScale, xScale } = useContext<BarChartContextValues>(BarChartContext)
|
|
17
17
|
|
|
@@ -30,40 +30,26 @@ const BarChartStackedHorizontal = () => {
|
|
|
30
30
|
} = useContext<ChartContext>(ConfigContext)
|
|
31
31
|
|
|
32
32
|
// prettier-ignore
|
|
33
|
-
const {
|
|
34
|
-
applyRadius,
|
|
35
|
-
barBorderWidth,
|
|
36
|
-
displayNumbersOnBar,
|
|
37
|
-
fontSize,
|
|
38
|
-
getAdditionalColumn,
|
|
39
|
-
hoveredBar,
|
|
40
|
-
isHorizontal,
|
|
41
|
-
isLabelBelowBar,
|
|
42
|
-
onMouseLeaveBar,
|
|
43
|
-
onMouseOverBar,
|
|
44
|
-
updateBars
|
|
45
|
-
} = useBarChart()
|
|
33
|
+
const { barBorderWidth, displayNumbersOnBar, fontSize, getAdditionalColumn, hoveredBar, isHorizontal, isLabelBelowBar, onMouseLeaveBar, onMouseOverBar, updateBars, barStackedSeriesKeys } = useBarChart()
|
|
46
34
|
|
|
47
35
|
const { orientation, visualizationSubType } = config
|
|
48
|
-
|
|
49
36
|
return (
|
|
50
37
|
config.visualizationSubType === 'stacked' &&
|
|
51
38
|
isHorizontal && (
|
|
52
39
|
<>
|
|
53
|
-
<BarStackHorizontal data={data} keys={
|
|
40
|
+
<BarStackHorizontal data={data} keys={barStackedSeriesKeys} height={yMax} y={d => d[config.runtime.yAxis.dataKey]} xScale={xScale} yScale={yScale} color={colorScale} offset='none'>
|
|
54
41
|
{barStacks =>
|
|
55
42
|
barStacks.map(barStack =>
|
|
56
43
|
updateBars(barStack.bars).map((bar, index) => {
|
|
57
|
-
|
|
58
|
-
|
|
44
|
+
const transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
|
|
45
|
+
const displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
|
|
59
46
|
config.barHeight = Number(config.barHeight)
|
|
60
|
-
|
|
47
|
+
const labelColor = getContrastColor('#000', colorScale(config.runtime.seriesLabels[bar.key]))
|
|
61
48
|
// tooltips
|
|
62
49
|
const xAxisValue = formatNumber(data[bar.index][bar.key], 'left')
|
|
63
50
|
const yAxisValue = config.runtime.yAxis.type === 'date' ? formatDate(parseDate(data[bar.index][config.runtime.originalXAxis.dataKey])) : data[bar.index][config.runtime.originalXAxis.dataKey]
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
let textWidth = getTextWidth(xAxisValue, `normal ${fontSize[config.fontSize]}px sans-serif`)
|
|
51
|
+
const yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
|
|
52
|
+
const textWidth = getTextWidth(xAxisValue, `normal ${fontSize[config.fontSize]}px sans-serif`)
|
|
67
53
|
|
|
68
54
|
const additionalColTooltip = getAdditionalColumn(hoveredBar)
|
|
69
55
|
const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${xAxisValue}`
|
|
@@ -73,46 +59,40 @@ const BarChartStackedHorizontal = () => {
|
|
|
73
59
|
<li class="tooltip-body ">${additionalColTooltip}</li>
|
|
74
60
|
</li></ul>`
|
|
75
61
|
|
|
76
|
-
if (chroma.contrast(labelColor, colorScale(config.runtime.seriesLabels[bar.key])) < 4.9) {
|
|
77
|
-
labelColor = '#FFFFFF'
|
|
78
|
-
}
|
|
79
|
-
|
|
80
62
|
return (
|
|
81
63
|
<>
|
|
82
|
-
<style>
|
|
83
|
-
{`
|
|
84
|
-
#barStack${barStack.index}-${bar.index} rect,
|
|
85
|
-
#barStack${barStack.index}-${bar.index} foreignObject div{
|
|
86
|
-
animation-delay: ${barStack.index * 0.5}s;
|
|
87
|
-
transform-origin: ${bar.x}px
|
|
88
|
-
}
|
|
89
|
-
`}
|
|
90
|
-
</style>
|
|
91
64
|
<Group key={index} id={`barStack${barStack.index}-${bar.index}`} className='stack horizontal'>
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
className
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
65
|
+
{createBarElement({
|
|
66
|
+
config: config,
|
|
67
|
+
seriesHighlight,
|
|
68
|
+
index: barStack.index,
|
|
69
|
+
className: `animated-chart group ${animatedChart ? 'animated' : ''}`,
|
|
70
|
+
background: colorScale(config.runtime.seriesLabels[bar.key]),
|
|
71
|
+
borderColor: '#333',
|
|
72
|
+
borderStyle: 'solid',
|
|
73
|
+
borderWidth: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px`,
|
|
74
|
+
width: bar.width,
|
|
75
|
+
height: bar.height,
|
|
76
|
+
x: bar.x,
|
|
77
|
+
y: bar.y,
|
|
78
|
+
onMouseOver: () => onMouseOverBar(yAxisValue, bar.key),
|
|
79
|
+
onMouseLeave: onMouseLeaveBar,
|
|
80
|
+
tooltipHtml: tooltip,
|
|
81
|
+
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
82
|
+
onClick: e => {
|
|
107
83
|
e.preventDefault()
|
|
108
84
|
if (setSharedFilter) {
|
|
109
85
|
bar[config.xAxis.dataKey] = xAxisValue
|
|
110
86
|
setSharedFilter(config.uid, bar)
|
|
111
87
|
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
88
|
+
},
|
|
89
|
+
styleOverrides: {
|
|
90
|
+
animationDelay: `${barStack.index * 0.5}s`,
|
|
91
|
+
transformOrigin: `${bar.x}px 0`,
|
|
92
|
+
opacity: transparentBar ? 0.2 : 1,
|
|
93
|
+
display: displayBar ? 'block' : 'none'
|
|
94
|
+
}
|
|
95
|
+
})}
|
|
116
96
|
|
|
117
97
|
{orientation === 'horizontal' && visualizationSubType === 'stacked' && isLabelBelowBar && barStack.index === 0 && !config.yAxis.hideLabel && (
|
|
118
98
|
<Text
|
|
@@ -6,12 +6,15 @@ import { Group } from '@visx/group'
|
|
|
6
6
|
import { Text } from '@visx/text'
|
|
7
7
|
import BarChartContext from './context'
|
|
8
8
|
import Regions from '../../Regions'
|
|
9
|
+
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
10
|
+
|
|
11
|
+
import createBarElement from '@cdc/core/components/createBarElement'
|
|
9
12
|
|
|
10
13
|
const BarChartStackedVertical = () => {
|
|
11
14
|
const [barWidth, setBarWidth] = useState(0)
|
|
12
15
|
const { xScale, yScale, xMax, yMax } = useContext(BarChartContext)
|
|
13
16
|
const { transformedData, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, setSharedFilter } = useContext(ConfigContext)
|
|
14
|
-
const { isHorizontal, barBorderWidth, applyRadius, hoveredBar, getAdditionalColumn, onMouseLeaveBar, onMouseOverBar } = useBarChart()
|
|
17
|
+
const { isHorizontal, barBorderWidth, applyRadius, hoveredBar, getAdditionalColumn, onMouseLeaveBar, onMouseOverBar, barStackedSeriesKeys } = useBarChart()
|
|
15
18
|
const { orientation } = config
|
|
16
19
|
const data = config.brush.active && config.brush.data?.length ? config.brush.data : transformedData
|
|
17
20
|
|
|
@@ -19,14 +22,14 @@ const BarChartStackedVertical = () => {
|
|
|
19
22
|
config.visualizationSubType === 'stacked' &&
|
|
20
23
|
!isHorizontal && (
|
|
21
24
|
<>
|
|
22
|
-
<BarStack data={data} keys={
|
|
25
|
+
<BarStack data={data} keys={barStackedSeriesKeys} x={d => d[config.runtime.xAxis.dataKey]} xScale={xScale} yScale={yScale} color={colorScale}>
|
|
23
26
|
{barStacks =>
|
|
24
27
|
barStacks.reverse().map(barStack =>
|
|
25
28
|
barStack.bars.map(bar => {
|
|
26
29
|
let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
|
|
27
30
|
let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
|
|
28
|
-
let barThickness = config.xAxis.type === 'date'
|
|
29
|
-
let barThicknessAdjusted = barThickness * (config.xAxis.type === 'date'
|
|
31
|
+
let barThickness = config.xAxis.type === 'date-time' ? config.barThickness * (xScale.range()[1] - xScale.range()[0]) : xMax / barStack.bars.length
|
|
32
|
+
let barThicknessAdjusted = barThickness * (config.xAxis.type === 'date-time' ? 1 : config.barThickness || 0.8)
|
|
30
33
|
let offset = (barThickness * (1 - (config.barThickness || 0.8))) / 2
|
|
31
34
|
// tooltips
|
|
32
35
|
const rawXValue = bar.bar.data[config.runtime.xAxis.dataKey]
|
|
@@ -48,50 +51,40 @@ const BarChartStackedVertical = () => {
|
|
|
48
51
|
|
|
49
52
|
return (
|
|
50
53
|
<Group key={`${barStack.index}--${bar.index}--${orientation}`}>
|
|
51
|
-
<style>
|
|
52
|
-
{`
|
|
53
|
-
#barStack${barStack.index}-${bar.index} rect,
|
|
54
|
-
#barStack${barStack.index}-${bar.index} foreignObject div{
|
|
55
|
-
animation-delay: ${barStack.index * 0.5}s;
|
|
56
|
-
transform-origin: ${barThicknessAdjusted / 2}px ${bar.y + bar.height}px
|
|
57
|
-
}
|
|
58
|
-
`}
|
|
59
|
-
</style>
|
|
60
54
|
<Group key={`bar-stack-${barStack.index}-${bar.index}`} id={`barStack${barStack.index}-${bar.index}`} className='stack vertical'>
|
|
61
55
|
<Text display={config.labels && displayBar ? 'block' : 'none'} opacity={transparentBar ? 0.5 : 1} x={barX + barWidth / 2} y={bar.y - 5} fill={'#000'} textAnchor='middle'>
|
|
62
56
|
{yAxisValue}
|
|
63
57
|
</Text>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
58
|
+
{createBarElement({
|
|
59
|
+
config: config,
|
|
60
|
+
seriesHighlight,
|
|
61
|
+
index: barStack.index,
|
|
62
|
+
background: colorScale(config.runtime.seriesLabels[bar.key]),
|
|
63
|
+
borderColor: '#333',
|
|
64
|
+
borderStyle: 'solid',
|
|
65
|
+
borderWidth: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px`,
|
|
66
|
+
width: barThicknessAdjusted,
|
|
67
|
+
height: bar.height,
|
|
68
|
+
x: barX,
|
|
69
|
+
y: bar.y,
|
|
70
|
+
onMouseOver: () => onMouseOverBar(xAxisValue, bar.key),
|
|
71
|
+
onMouseLeave: onMouseLeaveBar,
|
|
72
|
+
tooltipHtml: tooltip,
|
|
73
|
+
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
74
|
+
onClick: e => {
|
|
76
75
|
e.preventDefault()
|
|
77
76
|
if (setSharedFilter) {
|
|
78
77
|
bar[config.xAxis.dataKey] = xAxisValue
|
|
79
78
|
setSharedFilter(config.uid, bar)
|
|
80
79
|
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
background: colorScale(config.runtime.seriesLabels[bar.key]),
|
|
90
|
-
border: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px solid #333`,
|
|
91
|
-
...style
|
|
92
|
-
}}
|
|
93
|
-
></div>
|
|
94
|
-
</foreignObject>
|
|
80
|
+
},
|
|
81
|
+
styleOverrides: {
|
|
82
|
+
animationDelay: `${barStack.index * 0.5}s`,
|
|
83
|
+
transformOrigin: `${barThicknessAdjusted / 2}px ${bar.y + bar.height}px`,
|
|
84
|
+
opacity: transparentBar ? 0.2 : 1,
|
|
85
|
+
display: displayBar ? 'block' : 'none'
|
|
86
|
+
}
|
|
87
|
+
})}
|
|
95
88
|
</Group>
|
|
96
89
|
</Group>
|
|
97
90
|
)
|
|
@@ -8,6 +8,9 @@ import { BarGroup } from '@visx/shape'
|
|
|
8
8
|
import { useHighlightedBars } from '../../../hooks/useHighlightedBars'
|
|
9
9
|
import { FaStar } from 'react-icons/fa'
|
|
10
10
|
import Regions from './../../Regions'
|
|
11
|
+
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
12
|
+
|
|
13
|
+
import createBarElement from '@cdc/core/components/createBarElement'
|
|
11
14
|
|
|
12
15
|
// third party
|
|
13
16
|
import chroma from 'chroma-js'
|
|
@@ -75,7 +78,7 @@ export const BarChartVertical = () => {
|
|
|
75
78
|
height={yMax}
|
|
76
79
|
x0={d => {
|
|
77
80
|
const rawXValue = d[config.runtime.originalXAxis.dataKey]
|
|
78
|
-
return config.runtime.xAxis
|
|
81
|
+
return isDateScale(config.runtime.xAxis) ? parseDate(rawXValue) : rawXValue
|
|
79
82
|
}}
|
|
80
83
|
x0Scale={xScale}
|
|
81
84
|
x1Scale={seriesScale}
|
|
@@ -102,7 +105,7 @@ export const BarChartVertical = () => {
|
|
|
102
105
|
let barGroupWidth = seriesScale.range()[1]
|
|
103
106
|
|
|
104
107
|
let barWidth = config.isLollipopChart ? lollipopBarWidth : barGroupWidth / barGroup.bars.length
|
|
105
|
-
let barX = bar.x + (config.isLollipopChart ? (
|
|
108
|
+
let barX = bar.x + (config.isLollipopChart ? (barGroupWidth / barGroup.bars.length - lollipopBarWidth) / 2 : 0) - (config.xAxis.type === 'date-time' ? barGroupWidth / 2 : 0)
|
|
106
109
|
setBarWidth(barWidth)
|
|
107
110
|
setTotalBarsInGroup(barGroup.bars.length)
|
|
108
111
|
|
|
@@ -111,7 +114,6 @@ export const BarChartVertical = () => {
|
|
|
111
114
|
|
|
112
115
|
// create new Index for bars with negative values
|
|
113
116
|
const newIndex = bar.value < 0 ? -1 : index
|
|
114
|
-
const borderRadius = applyRadius(newIndex)
|
|
115
117
|
// tooltips
|
|
116
118
|
|
|
117
119
|
const additionalColTooltip = getAdditionalColumn(bar.key, data[barGroup.index][config.runtime.originalXAxis.dataKey])
|
|
@@ -179,57 +181,43 @@ export const BarChartVertical = () => {
|
|
|
179
181
|
return _barColor
|
|
180
182
|
}
|
|
181
183
|
|
|
182
|
-
const getLeft = () => {
|
|
183
|
-
if (barWidth < 50 && barWidth > 15) return barWidth / 2.5
|
|
184
|
-
if (barWidth < 15 && barWidth > 5) return barWidth / 6
|
|
185
|
-
if (barWidth < 5) return 0
|
|
186
|
-
return barWidth / 2
|
|
187
|
-
}
|
|
188
|
-
const iconStyle: { [key: string]: any } = {
|
|
189
|
-
position: 'absolute',
|
|
190
|
-
top: bar.value >= 0 && isNumber(bar.value) ? -suppresedBarHeight : undefined,
|
|
191
|
-
bottom: bar.value >= 0 && isNumber(bar.value) ? undefined : `-${suppresedBarHeight}px`,
|
|
192
|
-
left: getLeft()
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (config.isLollipopChart) {
|
|
196
|
-
iconStyle.left = 0
|
|
197
|
-
iconStyle.transform = `translateX(0)`
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const finalStyle = {
|
|
201
|
-
background: getBarBackgroundColor(barColor),
|
|
202
|
-
borderColor,
|
|
203
|
-
borderStyle: 'solid',
|
|
204
|
-
borderWidth: `${borderWidth}px`,
|
|
205
|
-
width: barWidth,
|
|
206
|
-
height: barHeight,
|
|
207
|
-
...borderRadius,
|
|
208
|
-
cursor: dashboardConfig ? 'pointer' : 'default'
|
|
209
|
-
}
|
|
210
|
-
|
|
211
184
|
return (
|
|
212
185
|
<Group key={`${barGroup.index}--${index}`}>
|
|
213
|
-
{/* This feels gross but inline transition was not working well*/}
|
|
214
|
-
<style>
|
|
215
|
-
{`
|
|
216
|
-
.linear #barGroup${barGroup.index} div,
|
|
217
|
-
.Combo #barGroup${barGroup.index} div {
|
|
218
|
-
transform-origin: 0 ${barY + barHeight}px;
|
|
219
|
-
}
|
|
220
|
-
`}
|
|
221
|
-
</style>
|
|
222
186
|
<Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
|
|
223
|
-
|
|
187
|
+
{createBarElement({
|
|
188
|
+
config: config,
|
|
189
|
+
index: newIndex,
|
|
190
|
+
id: `barGroup${barGroup.index}`,
|
|
191
|
+
background: getBarBackgroundColor(barColor),
|
|
192
|
+
borderColor,
|
|
193
|
+
borderStyle: 'solid',
|
|
194
|
+
borderWidth: `${borderWidth}px`,
|
|
195
|
+
width: barWidth,
|
|
196
|
+
height: barHeight,
|
|
197
|
+
x: barX,
|
|
198
|
+
y: barY,
|
|
199
|
+
onMouseOver: () => onMouseOverBar(xAxisValue, bar.key),
|
|
200
|
+
onMouseLeave: onMouseLeaveBar,
|
|
201
|
+
tooltipHtml: tooltip,
|
|
202
|
+
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
203
|
+
onClick: e => {
|
|
204
|
+
e.preventDefault()
|
|
205
|
+
if (setSharedFilter) {
|
|
206
|
+
bar[config.xAxis.dataKey] = xAxisValue
|
|
207
|
+
setSharedFilter(config.uid, bar)
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
styleOverrides: {
|
|
211
|
+
transformOrigin: `0 ${barY + barHeight}px`,
|
|
212
|
+
opacity: transparentBar ? 0.2 : 1,
|
|
213
|
+
display: displayBar ? 'block' : 'none',
|
|
214
|
+
cursor: dashboardConfig ? 'pointer' : 'default'
|
|
215
|
+
}
|
|
216
|
+
})}
|
|
217
|
+
<g
|
|
218
|
+
transform={`translate(${barX},${yMax - suppresedBarHeight})`}
|
|
224
219
|
onMouseOver={() => onMouseOverBar(xAxisValue, bar.key)}
|
|
225
220
|
onMouseLeave={onMouseLeaveBar}
|
|
226
|
-
style={{ overflow: 'visible', transition: 'all 0.2s linear' }}
|
|
227
|
-
id={`barGroup${barGroup.index}`}
|
|
228
|
-
key={`bar-group-bar-${barGroup.index}-${bar.index}-${bar.value}-${bar.key}`}
|
|
229
|
-
x={barX}
|
|
230
|
-
y={barY}
|
|
231
|
-
width={barWidth}
|
|
232
|
-
height={barHeight}
|
|
233
221
|
opacity={transparentBar ? 0.2 : 1}
|
|
234
222
|
display={displayBar ? 'block' : 'none'}
|
|
235
223
|
data-tooltip-html={tooltip}
|
|
@@ -242,11 +230,8 @@ export const BarChartVertical = () => {
|
|
|
242
230
|
}
|
|
243
231
|
}}
|
|
244
232
|
>
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
<div style={{ ...finalStyle }}></div>
|
|
248
|
-
</div>
|
|
249
|
-
</foreignObject>
|
|
233
|
+
{getIcon(bar, barWidth)}
|
|
234
|
+
</g>
|
|
250
235
|
|
|
251
236
|
<Text // prettier-ignore
|
|
252
237
|
display={config.labels && displayBar ? 'block' : 'none'}
|
|
@@ -303,7 +288,7 @@ export const BarChartVertical = () => {
|
|
|
303
288
|
let upperPos
|
|
304
289
|
let lowerPos
|
|
305
290
|
let tickWidth = 5
|
|
306
|
-
xPos = xScale(getXAxisData(d)) + (config.xAxis.type !== 'date' ||
|
|
291
|
+
xPos = xScale(getXAxisData(d)) + (config.xAxis.type !== 'date' || config.xAxis.type !== 'date-time' ? seriesScale.range()[1] / 2 : 0)
|
|
307
292
|
upperPos = yScale(getYAxisData(d, config.confidenceKeys.lower))
|
|
308
293
|
lowerPos = yScale(getYAxisData(d, config.confidenceKeys.upper))
|
|
309
294
|
return (
|
|
@@ -4,8 +4,8 @@ import { useContext, useEffect, useRef, useState } from 'react'
|
|
|
4
4
|
import ConfigContext from '../ConfigContext'
|
|
5
5
|
import { Text } from '@visx/text'
|
|
6
6
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
7
|
-
import chroma from 'chroma-js'
|
|
8
7
|
import useIntersectionObserver from '../hooks/useIntersectionObserver'
|
|
8
|
+
import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
|
|
9
9
|
|
|
10
10
|
export default function DeviationBar({ height, xScale }) {
|
|
11
11
|
const { transformedData: data, config, formatNumber, twoColorPalette, getTextWidth, updateConfig, parseDate, formatDate, currentViewport } = useContext(ConfigContext)
|
|
@@ -160,8 +160,7 @@ export default function DeviationBar({ height, xScale }) {
|
|
|
160
160
|
// colors
|
|
161
161
|
const [leftColor, rightColor] = twoColorPalette[twoColor.palette]
|
|
162
162
|
const barColor = { left: leftColor, right: rightColor }
|
|
163
|
-
const
|
|
164
|
-
const fill = isBarColorDark ? '#FFFFFF' : '#000000'
|
|
163
|
+
const fill = getContrastColor('#000', barColor[barPosition])
|
|
165
164
|
|
|
166
165
|
let textProps = getTextProps(config.isLollipopChart, textFits, lollipopShapeSize, fill)
|
|
167
166
|
// tooltips
|
|
@@ -187,6 +186,7 @@ export default function DeviationBar({ height, xScale }) {
|
|
|
187
186
|
height={barHeight}
|
|
188
187
|
data-tooltip-html={tooltip}
|
|
189
188
|
data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
|
|
189
|
+
tabIndex={-1}
|
|
190
190
|
>
|
|
191
191
|
<div style={{ width: barWidth, height: barHeight, border: `${borderWidth}px solid #333`, backgroundColor: barColor[barPosition], ...borderRadius }}></div>
|
|
192
192
|
</foreignObject>
|