@cdc/chart 4.25.3 → 4.25.6

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 (86) hide show
  1. package/dist/cdcchart.js +46641 -42561
  2. package/index.html +130 -129
  3. package/package.json +22 -27
  4. package/src/CdcChartComponent.tsx +75 -35
  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 +99 -86
  8. package/src/_stories/ChartPrefixSuffix.stories.tsx +29 -32
  9. package/{examples/private/line-issue.json → src/_stories/_mock/barchart_labels.mock.json} +150 -35
  10. package/src/_stories/_mock/dynamic_series_bar_config.json +1 -1
  11. package/src/_stories/_mock/dynamic_series_suppression_mock.json +610 -0
  12. package/{examples/private/not-loading.json → src/_stories/_mock/pie_calculated_area.json} +152 -95
  13. package/src/components/Annotations/components/AnnotationDropdown.tsx +2 -2
  14. package/src/components/AreaChart/components/AreaChart.jsx +33 -5
  15. package/src/components/Axis/Categorical.Axis.tsx +2 -2
  16. package/src/components/BarChart/components/BarChart.Horizontal.tsx +38 -37
  17. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +18 -8
  18. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +8 -8
  19. package/src/components/BarChart/components/BarChart.Vertical.tsx +47 -36
  20. package/src/components/BarChart/components/{BarChart.jsx → BarChart.tsx} +23 -5
  21. package/src/components/BarChart/components/context.tsx +20 -2
  22. package/src/components/BarChart/helpers/getBarHeights.ts +47 -0
  23. package/src/components/BarChart/helpers/index.ts +5 -2
  24. package/src/components/BarChart/helpers/tests/getBarHeights.test.ts +83 -0
  25. package/src/{hooks → components/BarChart/helpers}/useBarChart.ts +9 -46
  26. package/src/components/BoxPlot/BoxPlot.tsx +2 -1
  27. package/src/components/Brush/BrushChart.tsx +73 -0
  28. package/src/components/Brush/BrushController..tsx +39 -0
  29. package/src/components/DeviationBar.jsx +2 -2
  30. package/src/components/EditorPanel/EditorPanel.tsx +232 -147
  31. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +36 -36
  32. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +52 -25
  33. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +12 -4
  34. package/src/components/EditorPanel/components/Panels/panelVisual.styles.css +8 -0
  35. package/src/components/EditorPanel/useEditorPermissions.ts +5 -5
  36. package/src/components/ForestPlot/ForestPlot.tsx +2 -2
  37. package/src/components/HoverLine/HoverLine.tsx +74 -0
  38. package/src/components/Legend/Legend.Component.tsx +1 -1
  39. package/src/components/Legend/Legend.Suppression.tsx +59 -25
  40. package/src/components/Legend/helpers/createFormatLabels.tsx +28 -0
  41. package/src/components/Legend/helpers/index.ts +1 -1
  42. package/src/components/LineChart/LineChartProps.ts +3 -1
  43. package/src/components/LineChart/components/LineChart.Circle.tsx +72 -119
  44. package/src/components/LineChart/helpers.ts +133 -56
  45. package/src/components/LineChart/index.tsx +106 -55
  46. package/src/components/LinearChart.tsx +178 -198
  47. package/src/components/PairedBarChart.jsx +3 -2
  48. package/src/components/PieChart/PieChart.tsx +127 -102
  49. package/src/components/ScatterPlot/ScatterPlot.jsx +5 -0
  50. package/src/components/Sparkline/components/SparkLine.tsx +80 -18
  51. package/src/data/initial-state.js +11 -6
  52. package/src/helpers/countNumOfTicks.ts +1 -1
  53. package/src/helpers/dataHelpers.ts +23 -2
  54. package/src/helpers/getNewRuntime.ts +35 -0
  55. package/src/helpers/getPiePercent.ts +22 -0
  56. package/src/helpers/getTransformedData.ts +22 -0
  57. package/src/helpers/sizeHelpers.ts +1 -1
  58. package/src/helpers/tests/getNewRuntime.test.ts +82 -0
  59. package/src/helpers/tests/getPiePercent.test.ts +38 -0
  60. package/src/hooks/useMinMax.ts +21 -28
  61. package/src/hooks/useRightAxis.ts +5 -3
  62. package/src/hooks/useScales.ts +15 -6
  63. package/src/hooks/useTooltip.tsx +218 -203
  64. package/src/index.jsx +2 -2
  65. package/src/scss/main.scss +13 -6
  66. package/src/store/chart.actions.ts +2 -6
  67. package/src/store/chart.reducer.ts +23 -23
  68. package/src/types/ChartConfig.ts +11 -3
  69. package/src/types/ChartContext.ts +0 -2
  70. package/examples/private/DEV-8850-2.json +0 -493
  71. package/examples/private/DEV-9822.json +0 -574
  72. package/examples/private/DEV-9840.json +0 -553
  73. package/examples/private/DEV-9850-3.json +0 -461
  74. package/examples/private/chart.json +0 -1084
  75. package/examples/private/ci_formatted.json +0 -202
  76. package/examples/private/ci_issue.json +0 -3016
  77. package/examples/private/completed.json +0 -634
  78. package/examples/private/dem-data-long.csv +0 -20
  79. package/examples/private/dem-data-long.json +0 -36
  80. package/examples/private/demographic_data.csv +0 -157
  81. package/examples/private/demographic_data.json +0 -2654
  82. package/examples/private/demographic_dynamic.json +0 -443
  83. package/examples/private/demographic_standard.json +0 -560
  84. package/examples/private/ehdi.json +0 -29939
  85. package/examples/private/test.json +0 -493
  86. package/src/components/ZoomBrush.tsx +0 -251
@@ -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,23 @@ 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 { transformedData, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, setSharedFilter } =
25
+ useContext(ConfigContext)
26
+
28
27
  const { orientation } = config
29
28
 
30
- const data = config.brush?.active && config.brush.data?.length ? config.brush.data : transformedData
29
+ let data = transformedData
30
+
31
31
  const isDateAxisType = config.runtime.xAxis.type === 'date-time' || config.runtime.xAxis.type === 'date'
32
32
  const isDateTimeScaleAxisType = config.runtime.xAxis.type === 'date-time'
33
33
 
@@ -98,7 +98,7 @@ const BarChartStackedVertical = () => {
98
98
  height: bar.height,
99
99
  x: barX,
100
100
  y: bar.y,
101
- onMouseOver: () => onMouseOverBar(xAxisValue, bar.key),
101
+ onMouseOver: e => onMouseOverBar(xAxisValue, bar.key, e, data),
102
102
  onMouseLeave: onMouseLeaveBar,
103
103
  tooltipHtml: tooltip,
104
104
  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,28 @@ export const BarChartVertical = () => {
42
37
  onMouseLeaveBar,
43
38
  onMouseOverBar,
44
39
  section
45
- } = useBarChart()
40
+ } = barChart
46
41
 
47
- // prettier-ignore
48
- const { colorScale, config, dashboardConfig, tableData, formatDate, formatNumber, parseDate, seriesHighlight, setSharedFilter, transformedData, brushConfig } = useContext<ChartContext>(ConfigContext)
42
+ const [barWidth, setBarWidth] = useState(0)
43
+ const [totalBarsInGroup, setTotalBarsInGroup] = useState(0)
44
+
45
+ const {
46
+ colorScale,
47
+ config,
48
+ dashboardConfig,
49
+ tableData,
50
+ formatDate,
51
+ formatNumber,
52
+ parseDate,
53
+ seriesHighlight,
54
+ setSharedFilter,
55
+ transformedData
56
+ } = useContext<ChartContext>(ConfigContext)
49
57
 
50
58
  const { HighLightedBarUtils } = useHighlightedBars(config)
51
59
 
52
60
  const root = document.documentElement
53
61
 
54
- const coolGray90 = getComputedStyle(root).getPropertyValue('--cool-gray-90')
55
-
56
62
  let data = transformedData
57
63
  // check if user add suppression
58
64
  const isSuppressionActive = config.preliminaryData.some(pd => pd.value && pd.type === 'suppression')
@@ -60,12 +66,12 @@ export const BarChartVertical = () => {
60
66
  if (isSuppressionActive) {
61
67
  data = tableData
62
68
  }
63
- // if brush active use brush data (filtered|excluded) not cleaned
64
- if (brushConfig.data.length) {
65
- data = brushConfig.data
66
- }
67
69
 
68
- const hasConfidenceInterval = _.every(config.confidenceKeys, key => key !== '')
70
+ const hasConfidenceInterval =
71
+ config.confidenceKeys.upper &&
72
+ config.confidenceKeys.lower &&
73
+ config.confidenceKeys.upper !== '' &&
74
+ config.confidenceKeys.lower !== ''
69
75
 
70
76
  const _data = getBarData(config, data, hasConfidenceInterval)
71
77
  return (
@@ -144,7 +150,14 @@ export const BarChartVertical = () => {
144
150
  <li class="tooltip-body ">${tooltipBody}</li>
145
151
  ${additionalColTooltip ? '<li class="tooltip-body ">' + additionalColTooltip + '</li>' : ''}
146
152
  </li></ul>`
147
-
153
+ const { barHeight, isSuppressed, getBarY, absentDataLabel } = getBarConfig({
154
+ bar,
155
+ defaultBarHeight,
156
+ config,
157
+ barWidth,
158
+ isVertical: true,
159
+ yAxisValue
160
+ })
148
161
  // configure colors
149
162
  let labelColor = '#000000'
150
163
  labelColor = HighLightedBarUtils.checkFontColor(yAxisValue, highlightedBarValues, labelColor) // Set if background is transparent'
@@ -153,6 +166,12 @@ export const BarChartVertical = () => {
153
166
  const isHighlightedBar = highlightedBarValues?.includes(xAxisValue)
154
167
  const highlightedBarColor = getHighlightedBarColorByValue(xAxisValue)
155
168
  const highlightedBar = getHighlightedBarByValue(xAxisValue)
169
+ const hideGroup =
170
+ (!isNumber(bar.value) && !config.general.showMissingDataLabel) ||
171
+ (String(bar.value) === '0' && !config.general.showZeroValueData)
172
+ ? 'none'
173
+ : 'block' // hide bar group if no value or zero value
174
+
156
175
  const borderColor = isHighlightedBar
157
176
  ? highlightedBarColor
158
177
  : config.barHasBorder === 'true'
@@ -162,20 +181,11 @@ export const BarChartVertical = () => {
162
181
  ? highlightedBar.borderWidth
163
182
  : config.isLollipopChart
164
183
  ? 0
165
- : config.barHasBorder === 'true'
184
+ : config.barHasBorder === 'true' && !absentDataLabel && !isSuppressed
166
185
  ? barBorderWidth
167
186
  : 0
168
187
 
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
188
+ const barDefaultLabel = isSuppressed || absentDataLabel || !config.labels ? '' : yAxisValue
179
189
  const barY = getBarY(defaultBarY, yScale(scaleVal))
180
190
  const displaylollipopShape = testZeroValue(bar.value) ? 'none' : 'block'
181
191
  const getBarBackgroundColor = (barColor: string, filteredOutColor?: string): string => {
@@ -242,8 +252,10 @@ export const BarChartVertical = () => {
242
252
  )
243
253
  // End Confidence Interval Variables
244
254
 
255
+ const BAR_LABEL_PADDING = 10
256
+
245
257
  return (
246
- <Group key={`${barGroup.index}--${index}`}>
258
+ <Group display={hideGroup} key={`${barGroup.index}--${index}`}>
247
259
  <Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
248
260
  {createBarElement({
249
261
  config: config,
@@ -257,7 +269,7 @@ export const BarChartVertical = () => {
257
269
  height: barHeight,
258
270
  x: barX,
259
271
  y: barY,
260
- onMouseOver: () => onMouseOverBar(xAxisValue, bar.key),
272
+ onMouseOver: e => onMouseOverBar(xAxisValue, bar.key, e, data),
261
273
  onMouseLeave: onMouseLeaveBar,
262
274
  tooltipHtml: tooltip,
263
275
  tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
@@ -275,6 +287,7 @@ export const BarChartVertical = () => {
275
287
  cursor: dashboardConfig ? 'pointer' : 'default'
276
288
  }
277
289
  })}
290
+
278
291
  {config.preliminaryData.map((pd, index) => {
279
292
  // check if user selected column
280
293
  const selectedSuppressionColumn = !pd.column || pd.column === bar.key
@@ -318,12 +331,11 @@ export const BarChartVertical = () => {
318
331
  </Text>
319
332
  )
320
333
  })}
321
-
322
334
  <Text // prettier-ignore
323
335
  display={displayBar ? 'block' : 'none'}
324
336
  opacity={transparentBar ? 0.5 : 1}
325
337
  x={hasConfidenceInterval ? barX + barWidth : barX + barWidth / 2}
326
- y={barY - 5}
338
+ y={barY - BAR_LABEL_PADDING}
327
339
  fill={labelColor}
328
340
  textAnchor='middle'
329
341
  >
@@ -333,14 +345,13 @@ export const BarChartVertical = () => {
333
345
  display={displayBar ? 'block' : 'none'}
334
346
  opacity={transparentBar ? 0.5 : 1}
335
347
  x={barX + barWidth / 2}
336
- y={barY - 5}
348
+ y={barY - BAR_LABEL_PADDING}
337
349
  fill={labelColor}
338
350
  textAnchor='middle'
339
351
  fontSize={config.isLollipopChart ? null : barWidth / 2}
340
352
  >
341
353
  {absentDataLabel}
342
354
  </Text>
343
-
344
355
  {config.isLollipopChart && config.lollipopShape === 'circle' && (
345
356
  <circle
346
357
  display={displaylollipopShape}
@@ -373,7 +384,7 @@ export const BarChartVertical = () => {
373
384
  {hasConfidenceInterval && bar.value !== undefined && datum && (
374
385
  <path
375
386
  key={`confidence-interval-v-${datum[config.runtime.originalXAxis.dataKey]}`}
376
- stroke={coolGray90}
387
+ stroke={APP_FONT_COLOR}
377
388
  strokeWidth='px'
378
389
  d={`M${xPos - tickWidth} ${upperPos}
379
390
  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
+ }
@@ -9,6 +9,7 @@ interface BarConfigProps {
9
9
  config: { [key: string]: any }
10
10
  barWidth: number
11
11
  isVertical: boolean
12
+ yAxisValue: number
12
13
  }
13
14
 
14
15
  // Function to create bar width based on suppression status and missing data label
@@ -18,7 +19,8 @@ export const getBarConfig = ({
18
19
  defaultBarWidth,
19
20
  config,
20
21
  barWidth,
21
- isVertical
22
+ isVertical,
23
+ yAxisValue
22
24
  }: BarConfigProps) => {
23
25
  const heightMini = 3 /// height of small bars aka suppressed/NA/Zero valued
24
26
  let barHeight = defaultBarHeight
@@ -97,7 +99,8 @@ export const getBarConfig = ({
97
99
  return labelFits && isVertical ? label : !isVertical ? label : ''
98
100
  }
99
101
  }
100
- return { barWidthHorizontal, barHeight, isSuppressed, showMissingDataLabel, getBarY, getAbsentDataLabel }
102
+ const absentDataLabel = getAbsentDataLabel(yAxisValue)
103
+ return { barWidthHorizontal, barHeight, isSuppressed, showMissingDataLabel, getBarY, absentDataLabel }
101
104
  }
102
105
 
103
106
  export const testZeroValue = value => {
@@ -0,0 +1,83 @@
1
+ import { getHorizontalBarHeights } from '../getBarHeights'
2
+
3
+ describe('getHorizontalBarHeights', () => {
4
+ it('should calculate bar heights for non-stacked horizontal bars', () => {
5
+ const config = {
6
+ orientation: 'horizontal',
7
+ visualizationSubType: 'grouped',
8
+ runtime: { seriesKeys: ['A', 'B'] },
9
+ barHeight: 10,
10
+ barSpace: 5,
11
+ yAxis: { labelPlacement: 'Above Bar' }
12
+ }
13
+
14
+ const bars = [{ index: 0 }, { index: 1 }]
15
+
16
+ const result = getHorizontalBarHeights(config, bars)
17
+
18
+ expect(result).toEqual([
19
+ { index: 0, y: 0, height: 20 },
20
+ { index: 1, y: 25, height: 20 }
21
+ ])
22
+ })
23
+
24
+ it('should calculate bar heights for stacked horizontal bars', () => {
25
+ const config = {
26
+ orientation: 'horizontal',
27
+ visualizationSubType: 'stacked',
28
+ barHeight: 15,
29
+ barSpace: 5,
30
+ yAxis: { labelPlacement: 'Above Bar' }
31
+ }
32
+
33
+ const bars = [{ index: 0 }, { index: 1 }]
34
+
35
+ const result = getHorizontalBarHeights(config, bars)
36
+
37
+ expect(result).toEqual([
38
+ { index: 0, y: 0, height: 15 },
39
+ { index: 1, y: 20, height: 15 }
40
+ ])
41
+ })
42
+
43
+ it('should include label space when labelPlacement is Below Bar', () => {
44
+ const config = {
45
+ orientation: 'horizontal',
46
+ visualizationSubType: 'grouped',
47
+ runtime: { seriesKeys: ['A'] },
48
+ barHeight: 10,
49
+ barSpace: 5,
50
+ yAxis: { labelPlacement: 'Below Bar' }
51
+ }
52
+
53
+ const bars = [{ index: 0 }, { index: 1 }]
54
+
55
+ const result = getHorizontalBarHeights(config, bars)
56
+
57
+ expect(result).toEqual([
58
+ { index: 0, y: 0, height: 10 },
59
+ { index: 1, y: 37, height: 10 }
60
+ ])
61
+ })
62
+
63
+ it('should handle lollipop chart bar heights', () => {
64
+ const config = {
65
+ orientation: 'horizontal',
66
+ visualizationSubType: 'grouped',
67
+ runtime: { seriesKeys: ['A', 'B', 'C'] },
68
+ isLollipopChart: true,
69
+ lollipopSize: 'medium',
70
+ barSpace: 5,
71
+ yAxis: { labelPlacement: 'Above Bar' }
72
+ }
73
+
74
+ const bars = [{ index: 0 }, { index: 1 }]
75
+
76
+ const result = getHorizontalBarHeights(config, bars)
77
+
78
+ expect(result).toEqual([
79
+ { index: 0, y: 0, height: 18 },
80
+ { index: 1, y: 23, height: 18 }
81
+ ])
82
+ })
83
+ })
@@ -1,12 +1,12 @@
1
1
  import React, { useContext, useEffect, useState } from 'react'
2
- import ConfigContext, { ChartDispatchContext } from '../ConfigContext'
2
+ import { ChartDispatchContext } from '../../../ConfigContext'
3
3
  import { formatNumber as formatColNumber } from '@cdc/core/helpers/cove/number'
4
- import { appFontSize } from '@cdc/core/helpers/cove/fontSettings'
5
- export const useBarChart = () => {
6
- const { config, colorPalettes, tableData, updateConfig, parseDate, formatDate, setSeriesHighlight, seriesHighlight } =
7
- useContext(ConfigContext)
8
- const dispatch = useContext(ChartDispatchContext)
4
+ import { APP_FONT_SIZE } from '@cdc/core/helpers/constants'
5
+
6
+ export const useBarChart = (handleTooltipMouseOver, handleTooltipMouseOff, configContext) => {
7
+ const { config, colorPalettes, tableData, updateConfig, parseDate, formatDate, seriesHighlight } = configContext
9
8
  const { orientation } = config
9
+ const dispatch = useContext(ChartDispatchContext)
10
10
  const [hoveredBar, setHoveredBar] = useState(null)
11
11
 
12
12
  const isHorizontal = orientation === 'horizontal'
@@ -123,43 +123,6 @@ export const useBarChart = () => {
123
123
  const barColor = palette[barIndex]
124
124
  return barColor
125
125
  }
126
- const updateBars = defaultBars => {
127
- // function updates stacked && regular && lollipop horizontal bars
128
- if (config.visualizationType !== 'Bar' && !isHorizontal) return defaultBars
129
-
130
- const barsArr = [...defaultBars]
131
- let barHeight
132
-
133
- const heights = {
134
- stacked: config.barHeight,
135
- lollipop: lollipopBarWidth
136
- }
137
-
138
- if (!isStacked) {
139
- barHeight = heights[config.isLollipopChart ? 'lollipop' : 'stacked'] * stackCount
140
- } else {
141
- barHeight = heights.stacked
142
- }
143
-
144
- const labelHeight = isLabelBelowBar ? appFontSize * 1.2 : 0
145
- let barSpace = Number(config.barSpace)
146
-
147
- // calculate height of container based height, space and fontSize of labels
148
- let totalHeight = barsArr.length * (barHeight + labelHeight + barSpace)
149
-
150
- if (isHorizontal) {
151
- config.heights.horizontal = totalHeight
152
- }
153
-
154
- // return new updated bars/groupes
155
- return barsArr.map((bar, i) => {
156
- // set bars Y dynamically to handle space between bars
157
- let y = 0
158
- bar.index !== 0 && (y = (barHeight + barSpace + labelHeight) * i)
159
-
160
- return { ...bar, y: y, height: barHeight }
161
- })
162
- }
163
126
 
164
127
  const getHighlightedBarColorByValue = value => {
165
128
  const match = config?.highlightedBarValues.find(item => {
@@ -226,17 +189,18 @@ export const useBarChart = () => {
226
189
  return additionalTooltipItems
227
190
  }
228
191
 
229
- const onMouseOverBar = (categoryValue, barKey) => {
192
+ const onMouseOverBar = (categoryValue, barKey, event, data) => {
230
193
  if (config.legend.highlightOnHover && config.legend.behavior === 'highlight' && barKey) {
231
194
  dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: [barKey] })
232
195
  }
233
-
196
+ handleTooltipMouseOver(event, data)
234
197
  setHoveredBar(categoryValue)
235
198
  }
236
199
  const onMouseLeaveBar = () => {
237
200
  if (config.legend.highlightOnHover && config.legend.behavior === 'highlight') {
238
201
  dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: [] })
239
202
  }
203
+ handleTooltipMouseOff()
240
204
  }
241
205
 
242
206
  return {
@@ -256,7 +220,6 @@ export const useBarChart = () => {
256
220
  barStackedSeriesKeys,
257
221
  hasMultipleSeries,
258
222
  applyRadius,
259
- updateBars,
260
223
  assignColorsToValues,
261
224
  getHighlightedBarColorByValue,
262
225
  getHighlightedBarByValue,