@cdc/chart 4.25.3 → 4.25.5-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.
- package/dist/cdcchart.js +36051 -36995
- package/index.html +2 -1
- package/package.json +22 -27
- package/src/CdcChartComponent.tsx +10 -10
- package/src/_stories/Chart.CI.stories.tsx +10 -0
- package/src/_stories/Chart.DynamicSeries.stories.tsx +68 -49
- package/src/_stories/Chart.stories.tsx +7 -0
- package/{examples/private/line-issue.json → src/_stories/_mock/barchart_labels.mock.json} +150 -35
- package/src/_stories/_mock/dynamic_series_bar_config.json +1 -1
- package/src/_stories/_mock/dynamic_series_suppression_mock.json +610 -0
- package/src/components/Annotations/components/AnnotationDropdown.tsx +2 -2
- package/src/components/AreaChart/components/AreaChart.jsx +33 -5
- package/src/components/Axis/Categorical.Axis.tsx +2 -2
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +50 -40
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +18 -8
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +19 -8
- package/src/components/BarChart/components/BarChart.Vertical.tsx +47 -30
- package/src/components/BarChart/components/{BarChart.jsx → BarChart.tsx} +23 -5
- package/src/components/BarChart/components/context.tsx +20 -2
- package/src/components/BarChart/helpers/getBarHeights.ts +47 -0
- package/src/components/BarChart/helpers/index.ts +5 -2
- package/src/components/BarChart/helpers/tests/getBarHeights.test.ts +83 -0
- package/src/{hooks → components/BarChart/helpers}/useBarChart.ts +9 -46
- package/src/components/BoxPlot/BoxPlot.tsx +2 -1
- package/src/components/DeviationBar.jsx +2 -1
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +34 -34
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +51 -25
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +10 -3
- package/src/components/EditorPanel/useEditorPermissions.ts +1 -4
- package/src/components/ForestPlot/ForestPlot.tsx +2 -2
- package/src/components/Legend/Legend.Component.tsx +1 -1
- package/src/components/Legend/Legend.Suppression.tsx +12 -22
- package/src/components/Legend/helpers/createFormatLabels.tsx +28 -0
- package/src/components/LineChart/LineChartProps.ts +3 -1
- package/src/components/LineChart/components/LineChart.Circle.tsx +72 -119
- package/src/components/LineChart/helpers.ts +133 -56
- package/src/components/LineChart/index.tsx +107 -53
- package/src/components/LinearChart.tsx +40 -89
- package/src/components/PairedBarChart.jsx +3 -2
- package/src/components/PieChart/PieChart.tsx +71 -91
- package/src/components/ScatterPlot/ScatterPlot.jsx +5 -0
- package/src/components/Sparkline/components/SparkLine.tsx +80 -18
- package/src/components/ZoomBrush.tsx +4 -4
- package/src/data/initial-state.js +3 -1
- package/src/helpers/countNumOfTicks.ts +1 -1
- package/src/helpers/dataHelpers.ts +23 -2
- package/src/helpers/sizeHelpers.ts +1 -1
- package/src/hooks/useMinMax.ts +21 -28
- package/src/hooks/useRightAxis.ts +4 -2
- package/src/hooks/useScales.ts +10 -6
- package/src/hooks/useTooltip.tsx +204 -203
- package/src/index.jsx +2 -2
- package/src/scss/main.scss +13 -6
- package/src/types/ChartConfig.ts +5 -0
- package/LICENSE +0 -201
- package/examples/private/DEV-8850-2.json +0 -493
- package/examples/private/DEV-9822.json +0 -574
- package/examples/private/DEV-9840.json +0 -553
- package/examples/private/DEV-9850-3.json +0 -461
- package/examples/private/chart.json +0 -1084
- package/examples/private/ci_formatted.json +0 -202
- package/examples/private/ci_issue.json +0 -3016
- package/examples/private/completed.json +0 -634
- package/examples/private/dem-data-long.csv +0 -20
- package/examples/private/dem-data-long.json +0 -36
- package/examples/private/demographic_data.csv +0 -157
- package/examples/private/demographic_data.json +0 -2654
- package/examples/private/demographic_dynamic.json +0 -443
- package/examples/private/demographic_standard.json +0 -560
- package/examples/private/ehdi.json +0 -29939
- package/examples/private/not-loading.json +0 -360
- package/examples/private/test.json +0 -493
|
@@ -7,7 +7,7 @@ import ConfigContext from '../../ConfigContext'
|
|
|
7
7
|
import chroma from 'chroma-js'
|
|
8
8
|
import createBarElement from '@cdc/core/components/createBarElement'
|
|
9
9
|
import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
|
|
10
|
-
import {
|
|
10
|
+
import { APP_FONT_SIZE } from '@cdc/core/helpers/constants'
|
|
11
11
|
|
|
12
12
|
const CategoricalYAxis = ({ yMax, leftSize, max, xMax }) => {
|
|
13
13
|
const { config } = useContext(ConfigContext)
|
|
@@ -94,7 +94,7 @@ const CategoricalYAxis = ({ yMax, leftSize, max, xMax }) => {
|
|
|
94
94
|
barStacks.map(barStack =>
|
|
95
95
|
barStack.bars.map(bar => {
|
|
96
96
|
const isLastIndex = config.yAxis.categories.length - 1 === barStack.index
|
|
97
|
-
const textSize =
|
|
97
|
+
const textSize = APP_FONT_SIZE / 1.3
|
|
98
98
|
const textColor = chroma(bar.color).luminance() < 0.4 ? '#fff' : '#000'
|
|
99
99
|
const textWidth = getTextWidth(bar.key, `${textSize}px`)
|
|
100
100
|
const displayText = Number(textWidth) < bar.width && bar.height > textSize
|
|
@@ -2,7 +2,6 @@ import React, { useContext } from 'react'
|
|
|
2
2
|
|
|
3
3
|
// Local context and hooks
|
|
4
4
|
import ConfigContext from '../../../ConfigContext'
|
|
5
|
-
import { useBarChart } from '../../../hooks/useBarChart'
|
|
6
5
|
import { useHighlightedBars } from '../../../hooks/useHighlightedBars'
|
|
7
6
|
|
|
8
7
|
// VisX library imports
|
|
@@ -12,9 +11,11 @@ import { BarGroup } from '@visx/shape'
|
|
|
12
11
|
|
|
13
12
|
// CDC core components and helpers
|
|
14
13
|
import { getColorContrast, getContrastColor } from '@cdc/core/helpers/cove/accessibility'
|
|
14
|
+
import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
|
|
15
15
|
import createBarElement from '@cdc/core/components/createBarElement'
|
|
16
16
|
import { getBarConfig, testZeroValue } from '../helpers'
|
|
17
17
|
import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
|
|
18
|
+
import isNumber from '@cdc/core/helpers/isNumber'
|
|
18
19
|
|
|
19
20
|
// Third party libraries
|
|
20
21
|
import chroma from 'chroma-js'
|
|
@@ -24,29 +25,16 @@ import BarChartContext, { BarChartContextValues } from './context'
|
|
|
24
25
|
import { ChartContext } from '../../../types/ChartContext'
|
|
25
26
|
import _ from 'lodash'
|
|
26
27
|
import { getBarData } from '../helpers/getBarData'
|
|
28
|
+
import { getHorizontalBarHeights } from '../helpers/getBarHeights'
|
|
27
29
|
|
|
28
30
|
export const BarChartHorizontal = () => {
|
|
29
|
-
const { xScale, yScale, yMax, seriesScale } = useContext<BarChartContextValues>(BarChartContext)
|
|
30
|
-
const {
|
|
31
|
-
transformedData: data,
|
|
32
|
-
tableData,
|
|
33
|
-
colorScale,
|
|
34
|
-
seriesHighlight,
|
|
35
|
-
config,
|
|
36
|
-
formatNumber,
|
|
37
|
-
formatDate,
|
|
38
|
-
parseDate,
|
|
39
|
-
setSharedFilter,
|
|
40
|
-
isNumber
|
|
41
|
-
} = useContext<ChartContext>(ConfigContext)
|
|
31
|
+
const { xScale, yScale, yMax, seriesScale, barChart } = useContext<BarChartContextValues>(BarChartContext)
|
|
42
32
|
const {
|
|
43
33
|
isHorizontal,
|
|
44
34
|
barBorderWidth,
|
|
45
|
-
updateBars,
|
|
46
35
|
assignColorsToValues,
|
|
47
36
|
section,
|
|
48
37
|
isLabelBelowBar,
|
|
49
|
-
displayNumbersOnBar,
|
|
50
38
|
lollipopBarWidth,
|
|
51
39
|
lollipopShapeSize,
|
|
52
40
|
getHighlightedBarColorByValue,
|
|
@@ -55,18 +43,30 @@ export const BarChartHorizontal = () => {
|
|
|
55
43
|
hoveredBar,
|
|
56
44
|
onMouseLeaveBar,
|
|
57
45
|
onMouseOverBar
|
|
58
|
-
} =
|
|
46
|
+
} = barChart
|
|
47
|
+
|
|
48
|
+
const {
|
|
49
|
+
transformedData: data,
|
|
50
|
+
tableData,
|
|
51
|
+
colorScale,
|
|
52
|
+
seriesHighlight,
|
|
53
|
+
config,
|
|
54
|
+
formatNumber,
|
|
55
|
+
formatDate,
|
|
56
|
+
parseDate,
|
|
57
|
+
setSharedFilter
|
|
58
|
+
} = useContext<ChartContext>(ConfigContext)
|
|
59
59
|
|
|
60
60
|
const { HighLightedBarUtils } = useHighlightedBars(config)
|
|
61
61
|
|
|
62
|
-
const hasConfidenceInterval =
|
|
62
|
+
const hasConfidenceInterval =
|
|
63
|
+
config.confidenceKeys.upper &&
|
|
64
|
+
config.confidenceKeys.lower &&
|
|
65
|
+
config.confidenceKeys.upper !== '' &&
|
|
66
|
+
config.confidenceKeys.lower !== ''
|
|
63
67
|
|
|
64
68
|
const _data = getBarData(config, data, hasConfidenceInterval)
|
|
65
69
|
|
|
66
|
-
const root = document.documentElement
|
|
67
|
-
|
|
68
|
-
const coolGray90 = getComputedStyle(root).getPropertyValue('--cool-gray-90')
|
|
69
|
-
|
|
70
70
|
return (
|
|
71
71
|
config.visualizationSubType !== 'stacked' &&
|
|
72
72
|
config.visualizationType === 'Bar' &&
|
|
@@ -85,7 +85,7 @@ export const BarChartHorizontal = () => {
|
|
|
85
85
|
}}
|
|
86
86
|
>
|
|
87
87
|
{barGroups => {
|
|
88
|
-
return
|
|
88
|
+
return getHorizontalBarHeights(config, barGroups).map((barGroup, index) => (
|
|
89
89
|
<Group
|
|
90
90
|
className={`bar-group-${barGroup.index}-${barGroup.x0}--${index} ${config.orientation}`}
|
|
91
91
|
key={`bar-group-${barGroup.index}-${barGroup.x0}--${index}`}
|
|
@@ -120,19 +120,19 @@ export const BarChartHorizontal = () => {
|
|
|
120
120
|
const defaultBarWidth = Math.abs(xScale(bar.value) - xScale(scaleVal))
|
|
121
121
|
const isPositiveBar = bar.value >= 0 && isNumber(bar.value)
|
|
122
122
|
|
|
123
|
-
const {
|
|
124
|
-
barWidthHorizontal: barWidth,
|
|
125
|
-
isSuppressed,
|
|
126
|
-
getAbsentDataLabel
|
|
127
|
-
} = getBarConfig({ bar, defaultBarWidth, config, isNumber, isVertical: false })
|
|
128
123
|
const barX = bar.value < 0 ? Math.abs(xScale(bar.value)) : xScale(scaleVal)
|
|
129
124
|
const yAxisValue = formatNumber(bar.value, 'left')
|
|
130
125
|
const xAxisValue =
|
|
131
126
|
config.runtime[section].type === 'date' ? formatDate(parseDate(dataValue)) : dataValue
|
|
127
|
+
const {
|
|
128
|
+
barWidthHorizontal: barWidth,
|
|
129
|
+
isSuppressed,
|
|
130
|
+
absentDataLabel
|
|
131
|
+
} = getBarConfig({ bar, defaultBarWidth, config, isVertical: false, yAxisValue, barWidth: 0 })
|
|
132
132
|
|
|
133
133
|
const barPosition = !isPositiveBar ? 'below' : 'above'
|
|
134
|
-
|
|
135
|
-
const barDefaultLabel = !config.yAxis.displayNumbersOnBar ? '' : yAxisValue
|
|
134
|
+
|
|
135
|
+
const barDefaultLabel = !config.yAxis.displayNumbersOnBar || absentDataLabel ? '' : yAxisValue
|
|
136
136
|
|
|
137
137
|
// check if bar text/value string fits into each bars.
|
|
138
138
|
const textWidth = getTextWidth(barDefaultLabel)
|
|
@@ -192,15 +192,20 @@ export const BarChartHorizontal = () => {
|
|
|
192
192
|
? highlightedBar.borderWidth
|
|
193
193
|
: config.isLollipopChart
|
|
194
194
|
? 0
|
|
195
|
-
: config.barHasBorder === 'true'
|
|
195
|
+
: config.barHasBorder === 'true' && !absentDataLabel && !isSuppressed
|
|
196
196
|
? barBorderWidth
|
|
197
197
|
: 0
|
|
198
198
|
const displaylollipopShape = testZeroValue(bar.value) ? 'none' : 'block'
|
|
199
|
+
const hideGroup =
|
|
200
|
+
(!isNumber(bar.value) && !config.general.showMissingDataLabel) ||
|
|
201
|
+
(String(bar.value) === '0' && !config.general.showZeroValueData)
|
|
202
|
+
? 'none'
|
|
203
|
+
: 'block' // hide bar group if no value or zero value
|
|
199
204
|
|
|
200
205
|
// update label color
|
|
201
206
|
if (barColor && labelColor && textFits) {
|
|
202
|
-
labelColor = getContrastColor(
|
|
203
|
-
let constrast = getColorContrast(
|
|
207
|
+
labelColor = getContrastColor(APP_FONT_COLOR, barColor)
|
|
208
|
+
let constrast = getColorContrast(APP_FONT_COLOR, barColor)
|
|
204
209
|
const contrastLevel = 7
|
|
205
210
|
if (constrast < contrastLevel) {
|
|
206
211
|
labelColor = '#fff'
|
|
@@ -227,10 +232,11 @@ export const BarChartHorizontal = () => {
|
|
|
227
232
|
const d = datum[config.confidenceKeys[position]]
|
|
228
233
|
return xScale(d)
|
|
229
234
|
})
|
|
230
|
-
|
|
235
|
+
const labelX = bar.y
|
|
236
|
+
const overlapWithCI = hasConfidenceInterval && labelX >= lowerPos && labelX <= upperPos
|
|
231
237
|
|
|
232
238
|
return (
|
|
233
|
-
<Group key={`${barGroup.index}--${index}`}>
|
|
239
|
+
<Group display={hideGroup} key={`${barGroup.index}--${index}`}>
|
|
234
240
|
<Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
|
|
235
241
|
{createBarElement({
|
|
236
242
|
config: config,
|
|
@@ -244,7 +250,7 @@ export const BarChartHorizontal = () => {
|
|
|
244
250
|
height: numbericBarHeight,
|
|
245
251
|
x: barX,
|
|
246
252
|
y: barHeight * bar.index,
|
|
247
|
-
onMouseOver:
|
|
253
|
+
onMouseOver: e => onMouseOverBar(xAxisValue, bar.key, e, data),
|
|
248
254
|
onMouseLeave: onMouseLeaveBar,
|
|
249
255
|
tooltipHtml: tooltip,
|
|
250
256
|
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
@@ -305,8 +311,12 @@ export const BarChartHorizontal = () => {
|
|
|
305
311
|
display={displayBar ? 'block' : 'none'}
|
|
306
312
|
x={bar.y}
|
|
307
313
|
opacity={transparentBar ? 0.5 : 1}
|
|
308
|
-
y={
|
|
309
|
-
|
|
314
|
+
y={
|
|
315
|
+
hasConfidenceInterval && overlapWithCI
|
|
316
|
+
? config.barHeight * bar.index
|
|
317
|
+
: config.barHeight / 2 + config.barHeight * bar.index
|
|
318
|
+
}
|
|
319
|
+
fill={hasConfidenceInterval && overlapWithCI ? '#000' : labelColor}
|
|
310
320
|
dx={textPadding}
|
|
311
321
|
verticalAnchor='middle'
|
|
312
322
|
textAnchor={textAnchor}
|
|
@@ -387,10 +397,10 @@ export const BarChartHorizontal = () => {
|
|
|
387
397
|
<animate attributeName='height' values={`0, ${lollipopShapeSize}`} dur='2.5s' />
|
|
388
398
|
</rect>
|
|
389
399
|
)}
|
|
390
|
-
{hasConfidenceInterval && (
|
|
400
|
+
{hasConfidenceInterval && displayBar && (
|
|
391
401
|
<path
|
|
392
402
|
key={`confidence-interval-h-${yPos}-${datum[config.runtime.originalXAxis.dataKey]}`}
|
|
393
|
-
stroke={
|
|
403
|
+
stroke={APP_FONT_COLOR}
|
|
394
404
|
strokeWidth='px'
|
|
395
405
|
d={`
|
|
396
406
|
M${lowerPos} ${yPos - tickWidth}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import React, { useContext } from 'react'
|
|
2
2
|
import ConfigContext from '../../../ConfigContext'
|
|
3
|
-
import { useBarChart } from '../../../hooks/useBarChart'
|
|
4
3
|
import { BarStackHorizontal } from '@visx/shape'
|
|
5
4
|
import { Group } from '@visx/group'
|
|
6
5
|
import { Text } from '@visx/text'
|
|
7
6
|
import { getColorContrast, getContrastColor } from '@cdc/core/helpers/cove/accessibility'
|
|
7
|
+
import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
|
|
8
8
|
import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
|
|
9
9
|
|
|
10
10
|
// types
|
|
@@ -12,9 +12,10 @@ import BarChartContext, { type BarChartContextValues } from './context'
|
|
|
12
12
|
import { type ChartContext } from '../../../types/ChartContext'
|
|
13
13
|
|
|
14
14
|
import createBarElement from '@cdc/core/components/createBarElement'
|
|
15
|
+
import { getHorizontalBarHeights } from '../helpers/getBarHeights'
|
|
15
16
|
|
|
16
17
|
const BarChartStackedHorizontal = () => {
|
|
17
|
-
const { yMax, yScale, xScale } = useContext<BarChartContextValues>(BarChartContext)
|
|
18
|
+
const { yMax, yScale, xScale, barChart } = useContext<BarChartContextValues>(BarChartContext)
|
|
18
19
|
|
|
19
20
|
// prettier-ignore
|
|
20
21
|
const {
|
|
@@ -29,8 +30,17 @@ const BarChartStackedHorizontal = () => {
|
|
|
29
30
|
transformedData: data
|
|
30
31
|
} = useContext<ChartContext>(ConfigContext)
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
33
|
+
const {
|
|
34
|
+
barBorderWidth,
|
|
35
|
+
displayNumbersOnBar,
|
|
36
|
+
getAdditionalColumn,
|
|
37
|
+
hoveredBar,
|
|
38
|
+
isHorizontal,
|
|
39
|
+
isLabelBelowBar,
|
|
40
|
+
onMouseLeaveBar,
|
|
41
|
+
onMouseOverBar,
|
|
42
|
+
barStackedSeriesKeys
|
|
43
|
+
} = barChart
|
|
34
44
|
|
|
35
45
|
const { orientation, visualizationSubType } = config
|
|
36
46
|
return (
|
|
@@ -49,7 +59,7 @@ const BarChartStackedHorizontal = () => {
|
|
|
49
59
|
>
|
|
50
60
|
{barStacks =>
|
|
51
61
|
barStacks.map(barStack =>
|
|
52
|
-
|
|
62
|
+
getHorizontalBarHeights(config, barStack.bars).map((bar, index) => {
|
|
53
63
|
const transparentBar =
|
|
54
64
|
config.legend.behavior === 'highlight' &&
|
|
55
65
|
seriesHighlight.length > 0 &&
|
|
@@ -60,8 +70,8 @@ const BarChartStackedHorizontal = () => {
|
|
|
60
70
|
seriesHighlight.indexOf(bar.key) !== -1
|
|
61
71
|
config.barHeight = Number(config.barHeight)
|
|
62
72
|
let barColor = colorScale(config.runtime.seriesLabels[bar.key])
|
|
63
|
-
let labelColor = getContrastColor(
|
|
64
|
-
let constrast = getColorContrast(
|
|
73
|
+
let labelColor = getContrastColor(APP_FONT_COLOR, barColor)
|
|
74
|
+
let constrast = getColorContrast(APP_FONT_COLOR, barColor)
|
|
65
75
|
const contrastLevel = 7
|
|
66
76
|
if (constrast < contrastLevel) {
|
|
67
77
|
labelColor = '#fff'
|
|
@@ -100,7 +110,7 @@ const BarChartStackedHorizontal = () => {
|
|
|
100
110
|
height: bar.height,
|
|
101
111
|
x: bar.x,
|
|
102
112
|
y: bar.y,
|
|
103
|
-
onMouseOver:
|
|
113
|
+
onMouseOver: e => onMouseOverBar(yAxisValue, bar.key, e, data),
|
|
104
114
|
onMouseLeave: onMouseLeaveBar,
|
|
105
115
|
tooltipHtml: tooltip,
|
|
106
116
|
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import React, { useContext, useState } from 'react'
|
|
2
2
|
import ConfigContext from '../../../ConfigContext'
|
|
3
|
-
import { useBarChart } from '../../../hooks/useBarChart'
|
|
4
3
|
import { BarStack } from '@visx/shape'
|
|
5
4
|
import { Group } from '@visx/group'
|
|
6
5
|
import { Text } from '@visx/text'
|
|
@@ -12,22 +11,34 @@ import createBarElement from '@cdc/core/components/createBarElement'
|
|
|
12
11
|
|
|
13
12
|
const BarChartStackedVertical = () => {
|
|
14
13
|
const [barWidth, setBarWidth] = useState(0)
|
|
15
|
-
const { xScale, yScale, seriesScale, xMax, yMax } = useContext(BarChartContext)
|
|
16
|
-
const { transformedData, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, setSharedFilter } =
|
|
17
|
-
useContext(ConfigContext)
|
|
14
|
+
const { xScale, yScale, seriesScale, xMax, yMax, barChart } = useContext(BarChartContext)
|
|
18
15
|
const {
|
|
19
16
|
isHorizontal,
|
|
20
17
|
barBorderWidth,
|
|
21
|
-
applyRadius,
|
|
22
18
|
hoveredBar,
|
|
23
19
|
getAdditionalColumn,
|
|
24
20
|
onMouseLeaveBar,
|
|
25
21
|
onMouseOverBar,
|
|
26
22
|
barStackedSeriesKeys
|
|
27
|
-
} =
|
|
23
|
+
} = barChart
|
|
24
|
+
const {
|
|
25
|
+
transformedData,
|
|
26
|
+
colorScale,
|
|
27
|
+
seriesHighlight,
|
|
28
|
+
config,
|
|
29
|
+
formatNumber,
|
|
30
|
+
formatDate,
|
|
31
|
+
parseDate,
|
|
32
|
+
setSharedFilter,
|
|
33
|
+
brushConfig
|
|
34
|
+
} = useContext(ConfigContext)
|
|
35
|
+
|
|
28
36
|
const { orientation } = config
|
|
29
37
|
|
|
30
|
-
|
|
38
|
+
let data = transformedData
|
|
39
|
+
if (brushConfig.data.length) {
|
|
40
|
+
data = brushConfig.data
|
|
41
|
+
}
|
|
31
42
|
const isDateAxisType = config.runtime.xAxis.type === 'date-time' || config.runtime.xAxis.type === 'date'
|
|
32
43
|
const isDateTimeScaleAxisType = config.runtime.xAxis.type === 'date-time'
|
|
33
44
|
|
|
@@ -98,7 +109,7 @@ const BarChartStackedVertical = () => {
|
|
|
98
109
|
height: bar.height,
|
|
99
110
|
x: barX,
|
|
100
111
|
y: bar.y,
|
|
101
|
-
onMouseOver:
|
|
112
|
+
onMouseOver: e => onMouseOverBar(xAxisValue, bar.key, e, data),
|
|
102
113
|
onMouseLeave: onMouseLeaveBar,
|
|
103
114
|
tooltipHtml: tooltip,
|
|
104
115
|
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
@@ -3,7 +3,6 @@ import React, { useContext, useState } from 'react'
|
|
|
3
3
|
import ConfigContext from '../../../ConfigContext'
|
|
4
4
|
import BarChartContext, { type BarChartContextValues } from './context'
|
|
5
5
|
// Local hooks
|
|
6
|
-
import { useBarChart } from '../../../hooks/useBarChart'
|
|
7
6
|
import { useHighlightedBars } from '../../../hooks/useHighlightedBars'
|
|
8
7
|
import { getBarConfig, testZeroValue } from '../helpers'
|
|
9
8
|
// VisX library imports
|
|
@@ -16,6 +15,7 @@ import Regions from '../../Regions'
|
|
|
16
15
|
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
17
16
|
import isNumber from '@cdc/core/helpers/isNumber'
|
|
18
17
|
import createBarElement from '@cdc/core/components/createBarElement'
|
|
18
|
+
import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
|
|
19
19
|
// Third party libraries
|
|
20
20
|
import chroma from 'chroma-js'
|
|
21
21
|
// Types
|
|
@@ -24,14 +24,9 @@ import _ from 'lodash'
|
|
|
24
24
|
import { getBarData } from '../helpers/getBarData'
|
|
25
25
|
|
|
26
26
|
export const BarChartVertical = () => {
|
|
27
|
-
const { xScale, yScale, xMax, yMax, seriesScale, convertLineToBarGraph } =
|
|
27
|
+
const { xScale, yScale, xMax, yMax, seriesScale, convertLineToBarGraph, barChart } =
|
|
28
28
|
useContext<BarChartContextValues>(BarChartContext)
|
|
29
|
-
|
|
30
|
-
const [barWidth, setBarWidth] = useState(0)
|
|
31
|
-
const [totalBarsInGroup, setTotalBarsInGroup] = useState(0)
|
|
32
|
-
// prettier-ignore
|
|
33
29
|
const {
|
|
34
|
-
// prettier-ignore
|
|
35
30
|
assignColorsToValues,
|
|
36
31
|
barBorderWidth,
|
|
37
32
|
getAdditionalColumn,
|
|
@@ -42,17 +37,29 @@ export const BarChartVertical = () => {
|
|
|
42
37
|
onMouseLeaveBar,
|
|
43
38
|
onMouseOverBar,
|
|
44
39
|
section
|
|
45
|
-
} =
|
|
40
|
+
} = barChart
|
|
41
|
+
|
|
42
|
+
const [barWidth, setBarWidth] = useState(0)
|
|
43
|
+
const [totalBarsInGroup, setTotalBarsInGroup] = useState(0)
|
|
46
44
|
|
|
47
|
-
|
|
48
|
-
|
|
45
|
+
const {
|
|
46
|
+
colorScale,
|
|
47
|
+
config,
|
|
48
|
+
dashboardConfig,
|
|
49
|
+
tableData,
|
|
50
|
+
formatDate,
|
|
51
|
+
formatNumber,
|
|
52
|
+
parseDate,
|
|
53
|
+
seriesHighlight,
|
|
54
|
+
setSharedFilter,
|
|
55
|
+
transformedData,
|
|
56
|
+
brushConfig
|
|
57
|
+
} = useContext<ChartContext>(ConfigContext)
|
|
49
58
|
|
|
50
59
|
const { HighLightedBarUtils } = useHighlightedBars(config)
|
|
51
60
|
|
|
52
61
|
const root = document.documentElement
|
|
53
62
|
|
|
54
|
-
const coolGray90 = getComputedStyle(root).getPropertyValue('--cool-gray-90')
|
|
55
|
-
|
|
56
63
|
let data = transformedData
|
|
57
64
|
// check if user add suppression
|
|
58
65
|
const isSuppressionActive = config.preliminaryData.some(pd => pd.value && pd.type === 'suppression')
|
|
@@ -65,7 +72,11 @@ export const BarChartVertical = () => {
|
|
|
65
72
|
data = brushConfig.data
|
|
66
73
|
}
|
|
67
74
|
|
|
68
|
-
const hasConfidenceInterval =
|
|
75
|
+
const hasConfidenceInterval =
|
|
76
|
+
config.confidenceKeys.upper &&
|
|
77
|
+
config.confidenceKeys.lower &&
|
|
78
|
+
config.confidenceKeys.upper !== '' &&
|
|
79
|
+
config.confidenceKeys.lower !== ''
|
|
69
80
|
|
|
70
81
|
const _data = getBarData(config, data, hasConfidenceInterval)
|
|
71
82
|
return (
|
|
@@ -144,7 +155,14 @@ export const BarChartVertical = () => {
|
|
|
144
155
|
<li class="tooltip-body ">${tooltipBody}</li>
|
|
145
156
|
${additionalColTooltip ? '<li class="tooltip-body ">' + additionalColTooltip + '</li>' : ''}
|
|
146
157
|
</li></ul>`
|
|
147
|
-
|
|
158
|
+
const { barHeight, isSuppressed, getBarY, absentDataLabel } = getBarConfig({
|
|
159
|
+
bar,
|
|
160
|
+
defaultBarHeight,
|
|
161
|
+
config,
|
|
162
|
+
barWidth,
|
|
163
|
+
isVertical: true,
|
|
164
|
+
yAxisValue
|
|
165
|
+
})
|
|
148
166
|
// configure colors
|
|
149
167
|
let labelColor = '#000000'
|
|
150
168
|
labelColor = HighLightedBarUtils.checkFontColor(yAxisValue, highlightedBarValues, labelColor) // Set if background is transparent'
|
|
@@ -153,6 +171,12 @@ export const BarChartVertical = () => {
|
|
|
153
171
|
const isHighlightedBar = highlightedBarValues?.includes(xAxisValue)
|
|
154
172
|
const highlightedBarColor = getHighlightedBarColorByValue(xAxisValue)
|
|
155
173
|
const highlightedBar = getHighlightedBarByValue(xAxisValue)
|
|
174
|
+
const hideGroup =
|
|
175
|
+
(!isNumber(bar.value) && !config.general.showMissingDataLabel) ||
|
|
176
|
+
(String(bar.value) === '0' && !config.general.showZeroValueData)
|
|
177
|
+
? 'none'
|
|
178
|
+
: 'block' // hide bar group if no value or zero value
|
|
179
|
+
|
|
156
180
|
const borderColor = isHighlightedBar
|
|
157
181
|
? highlightedBarColor
|
|
158
182
|
: config.barHasBorder === 'true'
|
|
@@ -162,20 +186,11 @@ export const BarChartVertical = () => {
|
|
|
162
186
|
? highlightedBar.borderWidth
|
|
163
187
|
: config.isLollipopChart
|
|
164
188
|
? 0
|
|
165
|
-
: config.barHasBorder === 'true'
|
|
189
|
+
: config.barHasBorder === 'true' && !absentDataLabel && !isSuppressed
|
|
166
190
|
? barBorderWidth
|
|
167
191
|
: 0
|
|
168
192
|
|
|
169
|
-
const
|
|
170
|
-
bar,
|
|
171
|
-
defaultBarHeight,
|
|
172
|
-
config,
|
|
173
|
-
barWidth,
|
|
174
|
-
isVertical: true
|
|
175
|
-
})
|
|
176
|
-
|
|
177
|
-
const absentDataLabel = getAbsentDataLabel(yAxisValue)
|
|
178
|
-
const barDefaultLabel = isSuppressed || !config.labels ? '' : yAxisValue
|
|
193
|
+
const barDefaultLabel = isSuppressed || absentDataLabel || !config.labels ? '' : yAxisValue
|
|
179
194
|
const barY = getBarY(defaultBarY, yScale(scaleVal))
|
|
180
195
|
const displaylollipopShape = testZeroValue(bar.value) ? 'none' : 'block'
|
|
181
196
|
const getBarBackgroundColor = (barColor: string, filteredOutColor?: string): string => {
|
|
@@ -242,8 +257,10 @@ export const BarChartVertical = () => {
|
|
|
242
257
|
)
|
|
243
258
|
// End Confidence Interval Variables
|
|
244
259
|
|
|
260
|
+
const BAR_LABEL_PADDING = 10
|
|
261
|
+
|
|
245
262
|
return (
|
|
246
|
-
<Group key={`${barGroup.index}--${index}`}>
|
|
263
|
+
<Group display={hideGroup} key={`${barGroup.index}--${index}`}>
|
|
247
264
|
<Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
|
|
248
265
|
{createBarElement({
|
|
249
266
|
config: config,
|
|
@@ -257,7 +274,7 @@ export const BarChartVertical = () => {
|
|
|
257
274
|
height: barHeight,
|
|
258
275
|
x: barX,
|
|
259
276
|
y: barY,
|
|
260
|
-
onMouseOver:
|
|
277
|
+
onMouseOver: e => onMouseOverBar(xAxisValue, bar.key, e, data),
|
|
261
278
|
onMouseLeave: onMouseLeaveBar,
|
|
262
279
|
tooltipHtml: tooltip,
|
|
263
280
|
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
@@ -323,7 +340,7 @@ export const BarChartVertical = () => {
|
|
|
323
340
|
display={displayBar ? 'block' : 'none'}
|
|
324
341
|
opacity={transparentBar ? 0.5 : 1}
|
|
325
342
|
x={hasConfidenceInterval ? barX + barWidth : barX + barWidth / 2}
|
|
326
|
-
y={barY -
|
|
343
|
+
y={barY - BAR_LABEL_PADDING}
|
|
327
344
|
fill={labelColor}
|
|
328
345
|
textAnchor='middle'
|
|
329
346
|
>
|
|
@@ -333,7 +350,7 @@ export const BarChartVertical = () => {
|
|
|
333
350
|
display={displayBar ? 'block' : 'none'}
|
|
334
351
|
opacity={transparentBar ? 0.5 : 1}
|
|
335
352
|
x={barX + barWidth / 2}
|
|
336
|
-
y={barY -
|
|
353
|
+
y={barY - BAR_LABEL_PADDING}
|
|
337
354
|
fill={labelColor}
|
|
338
355
|
textAnchor='middle'
|
|
339
356
|
fontSize={config.isLollipopChart ? null : barWidth / 2}
|
|
@@ -373,7 +390,7 @@ export const BarChartVertical = () => {
|
|
|
373
390
|
{hasConfidenceInterval && bar.value !== undefined && datum && (
|
|
374
391
|
<path
|
|
375
392
|
key={`confidence-interval-v-${datum[config.runtime.originalXAxis.dataKey]}`}
|
|
376
|
-
stroke={
|
|
393
|
+
stroke={APP_FONT_COLOR}
|
|
377
394
|
strokeWidth='px'
|
|
378
395
|
d={`M${xPos - tickWidth} ${upperPos}
|
|
379
396
|
L${xPos + tickWidth} ${upperPos}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useContext } from 'react'
|
|
1
|
+
import React, { MouseEventHandler, useContext, useState } from 'react'
|
|
2
2
|
|
|
3
3
|
// visx
|
|
4
4
|
import { Group } from '@visx/group'
|
|
@@ -9,8 +9,21 @@ import BarChartType from './BarChartType'
|
|
|
9
9
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
10
10
|
import ConfigContext from '../../../ConfigContext'
|
|
11
11
|
import BarChartContext from './context'
|
|
12
|
+
import { useBarChart } from '../helpers/useBarChart'
|
|
13
|
+
import { PositionScale } from '@visx/shape/lib/types'
|
|
12
14
|
|
|
13
|
-
|
|
15
|
+
type BarChartProps = {
|
|
16
|
+
xScale: PositionScale
|
|
17
|
+
yScale: PositionScale
|
|
18
|
+
seriesScale: PositionScale
|
|
19
|
+
xMax: number
|
|
20
|
+
yMax: number
|
|
21
|
+
handleTooltipMouseOver: MouseEventHandler<SVGRectElement>
|
|
22
|
+
handleTooltipMouseOff: MouseEventHandler<SVGRectElement>
|
|
23
|
+
handleTooltipClick: MouseEventHandler<SVGRectElement>
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const BarChart: React.FC<BarChartProps> = ({
|
|
14
27
|
xScale,
|
|
15
28
|
yScale,
|
|
16
29
|
seriesScale,
|
|
@@ -20,7 +33,9 @@ const BarChart = ({
|
|
|
20
33
|
handleTooltipMouseOff,
|
|
21
34
|
handleTooltipClick
|
|
22
35
|
}) => {
|
|
23
|
-
const
|
|
36
|
+
const configContext = useContext(ConfigContext)
|
|
37
|
+
const { transformedData: data, config, convertLineToBarGraph } = configContext
|
|
38
|
+
const barChart = useBarChart(handleTooltipMouseOver, handleTooltipMouseOff, configContext)
|
|
24
39
|
|
|
25
40
|
const contextValues = {
|
|
26
41
|
xScale,
|
|
@@ -28,7 +43,8 @@ const BarChart = ({
|
|
|
28
43
|
xMax,
|
|
29
44
|
yMax,
|
|
30
45
|
seriesScale,
|
|
31
|
-
convertLineToBarGraph
|
|
46
|
+
convertLineToBarGraph,
|
|
47
|
+
barChart
|
|
32
48
|
}
|
|
33
49
|
|
|
34
50
|
return (
|
|
@@ -46,7 +62,9 @@ const BarChart = ({
|
|
|
46
62
|
height={Number(yMax)}
|
|
47
63
|
fill={'transparent'}
|
|
48
64
|
fillOpacity={0.05}
|
|
49
|
-
onMouseMove={e =>
|
|
65
|
+
onMouseMove={e => {
|
|
66
|
+
handleTooltipMouseOver(e, data)
|
|
67
|
+
}}
|
|
50
68
|
onMouseOut={handleTooltipMouseOff}
|
|
51
69
|
onClick={e => handleTooltipClick(e, data)}
|
|
52
70
|
/>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { PositionScale } from '@visx/shape/lib/types'
|
|
1
2
|
import { createContext } from 'react'
|
|
2
3
|
|
|
3
4
|
const BarChartContext = createContext(null)
|
|
@@ -5,10 +6,27 @@ const BarChartContext = createContext(null)
|
|
|
5
6
|
export type BarChartContextValues = {
|
|
6
7
|
xMax: number
|
|
7
8
|
yMax: number
|
|
8
|
-
xScale:
|
|
9
|
-
yScale:
|
|
9
|
+
xScale: PositionScale
|
|
10
|
+
yScale: PositionScale
|
|
10
11
|
seriesScale: Function
|
|
11
12
|
convertLineToBarGraph: boolean
|
|
13
|
+
barChart: {
|
|
14
|
+
assignColorsToValues: Function
|
|
15
|
+
barBorderWidth: number
|
|
16
|
+
getAdditionalColumn: Function
|
|
17
|
+
getHighlightedBarByValue: Function
|
|
18
|
+
getHighlightedBarColorByValue: Function
|
|
19
|
+
lollipopBarWidth: number
|
|
20
|
+
lollipopShapeSize: number
|
|
21
|
+
onMouseLeaveBar: Function
|
|
22
|
+
onMouseOverBar: Function
|
|
23
|
+
section: string
|
|
24
|
+
hoveredBar: string
|
|
25
|
+
isHorizontal: boolean
|
|
26
|
+
isLabelBelowBar: boolean
|
|
27
|
+
displayNumbersOnBar: boolean
|
|
28
|
+
barStackedSeriesKeys: string[]
|
|
29
|
+
}
|
|
12
30
|
}
|
|
13
31
|
|
|
14
32
|
export default BarChartContext
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { APP_FONT_SIZE } from '@cdc/core/helpers/constants'
|
|
2
|
+
import _ from 'lodash'
|
|
3
|
+
import { ChartConfig } from '../../../types/ChartConfig'
|
|
4
|
+
|
|
5
|
+
export const getHorizontalBarHeights = <T>(config: Partial<ChartConfig>, bars: (T & { index })[]) => {
|
|
6
|
+
const isHorizontal = config.orientation === 'horizontal'
|
|
7
|
+
|
|
8
|
+
const isStacked = config.visualizationSubType === 'stacked'
|
|
9
|
+
|
|
10
|
+
let barHeight
|
|
11
|
+
if (!isStacked) {
|
|
12
|
+
const stackCount = config.runtime.seriesKeys.length
|
|
13
|
+
if (config.isLollipopChart) {
|
|
14
|
+
const lollipopSizes = {
|
|
15
|
+
large: 7,
|
|
16
|
+
medium: 6,
|
|
17
|
+
small: 5
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const lollipopBarWidth = lollipopSizes[config.lollipopSize] || 5
|
|
21
|
+
barHeight = lollipopBarWidth * stackCount
|
|
22
|
+
} else {
|
|
23
|
+
barHeight = config.barHeight * stackCount
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
barHeight = config.barHeight
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const labelHeight = APP_FONT_SIZE * 1.2
|
|
30
|
+
const labelSpace = config.yAxis.labelPlacement === 'Below Bar' ? labelHeight : 0
|
|
31
|
+
|
|
32
|
+
const totalBarHeight = barHeight + labelSpace + Number(config.barSpace)
|
|
33
|
+
|
|
34
|
+
if (isHorizontal) {
|
|
35
|
+
// calculate height of container based height, space and fontSize of labels
|
|
36
|
+
const totalHeight = bars.length * totalBarHeight
|
|
37
|
+
if (!config.heights) config.heights = {}
|
|
38
|
+
config.heights.horizontal = totalHeight
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// return new updated bars/groupes
|
|
42
|
+
return bars.map((bar, i) => {
|
|
43
|
+
// set bars Y dynamically to handle space between bars
|
|
44
|
+
const y = bar.index === 0 ? 0 : _.round(totalBarHeight * i)
|
|
45
|
+
return { ...bar, y, height: barHeight }
|
|
46
|
+
})
|
|
47
|
+
}
|