@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.
Files changed (72) hide show
  1. package/dist/cdcchart.js +36051 -36995
  2. package/index.html +2 -1
  3. package/package.json +22 -27
  4. package/src/CdcChartComponent.tsx +10 -10
  5. package/src/_stories/Chart.CI.stories.tsx +10 -0
  6. package/src/_stories/Chart.DynamicSeries.stories.tsx +68 -49
  7. package/src/_stories/Chart.stories.tsx +7 -0
  8. package/{examples/private/line-issue.json → src/_stories/_mock/barchart_labels.mock.json} +150 -35
  9. package/src/_stories/_mock/dynamic_series_bar_config.json +1 -1
  10. package/src/_stories/_mock/dynamic_series_suppression_mock.json +610 -0
  11. package/src/components/Annotations/components/AnnotationDropdown.tsx +2 -2
  12. package/src/components/AreaChart/components/AreaChart.jsx +33 -5
  13. package/src/components/Axis/Categorical.Axis.tsx +2 -2
  14. package/src/components/BarChart/components/BarChart.Horizontal.tsx +50 -40
  15. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +18 -8
  16. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +19 -8
  17. package/src/components/BarChart/components/BarChart.Vertical.tsx +47 -30
  18. package/src/components/BarChart/components/{BarChart.jsx → BarChart.tsx} +23 -5
  19. package/src/components/BarChart/components/context.tsx +20 -2
  20. package/src/components/BarChart/helpers/getBarHeights.ts +47 -0
  21. package/src/components/BarChart/helpers/index.ts +5 -2
  22. package/src/components/BarChart/helpers/tests/getBarHeights.test.ts +83 -0
  23. package/src/{hooks → components/BarChart/helpers}/useBarChart.ts +9 -46
  24. package/src/components/BoxPlot/BoxPlot.tsx +2 -1
  25. package/src/components/DeviationBar.jsx +2 -1
  26. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +34 -34
  27. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +51 -25
  28. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +10 -3
  29. package/src/components/EditorPanel/useEditorPermissions.ts +1 -4
  30. package/src/components/ForestPlot/ForestPlot.tsx +2 -2
  31. package/src/components/Legend/Legend.Component.tsx +1 -1
  32. package/src/components/Legend/Legend.Suppression.tsx +12 -22
  33. package/src/components/Legend/helpers/createFormatLabels.tsx +28 -0
  34. package/src/components/LineChart/LineChartProps.ts +3 -1
  35. package/src/components/LineChart/components/LineChart.Circle.tsx +72 -119
  36. package/src/components/LineChart/helpers.ts +133 -56
  37. package/src/components/LineChart/index.tsx +107 -53
  38. package/src/components/LinearChart.tsx +40 -89
  39. package/src/components/PairedBarChart.jsx +3 -2
  40. package/src/components/PieChart/PieChart.tsx +71 -91
  41. package/src/components/ScatterPlot/ScatterPlot.jsx +5 -0
  42. package/src/components/Sparkline/components/SparkLine.tsx +80 -18
  43. package/src/components/ZoomBrush.tsx +4 -4
  44. package/src/data/initial-state.js +3 -1
  45. package/src/helpers/countNumOfTicks.ts +1 -1
  46. package/src/helpers/dataHelpers.ts +23 -2
  47. package/src/helpers/sizeHelpers.ts +1 -1
  48. package/src/hooks/useMinMax.ts +21 -28
  49. package/src/hooks/useRightAxis.ts +4 -2
  50. package/src/hooks/useScales.ts +10 -6
  51. package/src/hooks/useTooltip.tsx +204 -203
  52. package/src/index.jsx +2 -2
  53. package/src/scss/main.scss +13 -6
  54. package/src/types/ChartConfig.ts +5 -0
  55. package/LICENSE +0 -201
  56. package/examples/private/DEV-8850-2.json +0 -493
  57. package/examples/private/DEV-9822.json +0 -574
  58. package/examples/private/DEV-9840.json +0 -553
  59. package/examples/private/DEV-9850-3.json +0 -461
  60. package/examples/private/chart.json +0 -1084
  61. package/examples/private/ci_formatted.json +0 -202
  62. package/examples/private/ci_issue.json +0 -3016
  63. package/examples/private/completed.json +0 -634
  64. package/examples/private/dem-data-long.csv +0 -20
  65. package/examples/private/dem-data-long.json +0 -36
  66. package/examples/private/demographic_data.csv +0 -157
  67. package/examples/private/demographic_data.json +0 -2654
  68. package/examples/private/demographic_dynamic.json +0 -443
  69. package/examples/private/demographic_standard.json +0 -560
  70. package/examples/private/ehdi.json +0 -29939
  71. package/examples/private/not-loading.json +0 -360
  72. 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 { appFontSize } from '@cdc/core/helpers/cove/fontSettings'
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 = appFontSize / 1.3
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
- } = useBarChart()
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 = Object.keys(config.confidenceKeys).length > 0
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 updateBars(barGroups).map((barGroup, index) => (
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
- const absentDataLabel = getAbsentDataLabel(yAxisValue)
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('#000', barColor)
203
- let constrast = getColorContrast('#000', barColor)
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
- // End Confidence Interval Variables
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: () => onMouseOverBar(xAxisValue, bar.key),
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={config.barHeight / 2 + config.barHeight * bar.index}
309
- fill={labelColor}
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={coolGray90}
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
- // prettier-ignore
33
- const { barBorderWidth, displayNumbersOnBar, getAdditionalColumn, hoveredBar, isHorizontal, isLabelBelowBar, onMouseLeaveBar, onMouseOverBar, updateBars, barStackedSeriesKeys } = useBarChart()
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
- updateBars(barStack.bars).map((bar, index) => {
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('#000', barColor)
64
- let constrast = getColorContrast('#000', barColor)
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: () => onMouseOverBar(yAxisValue, bar.key),
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
- } = useBarChart()
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
- const data = config.brush?.active && config.brush.data?.length ? config.brush.data : transformedData
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: () => onMouseOverBar(xAxisValue, bar.key),
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
- } = useBarChart()
40
+ } = barChart
41
+
42
+ const [barWidth, setBarWidth] = useState(0)
43
+ const [totalBarsInGroup, setTotalBarsInGroup] = useState(0)
46
44
 
47
- // prettier-ignore
48
- const { colorScale, config, dashboardConfig, tableData, formatDate, formatNumber, parseDate, seriesHighlight, setSharedFilter, transformedData, brushConfig } = useContext<ChartContext>(ConfigContext)
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 = _.every(config.confidenceKeys, key => key !== '')
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 { barHeight, isSuppressed, getBarY, getAbsentDataLabel } = getBarConfig({
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: () => onMouseOverBar(xAxisValue, bar.key),
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 - 5}
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 - 5}
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={coolGray90}
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
- const BarChart = ({
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 { transformedData: data, config, convertLineToBarGraph } = useContext(ConfigContext)
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 => handleTooltipMouseOver(e, data)}
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: Function
9
- yScale: Function
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
+ }