@cdc/chart 4.25.3-6 → 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-1a1724a1.es.js +4886 -0
- package/dist/cdcchart.js +50347 -75521
- package/index.html +1 -0
- package/package.json +22 -27
- package/src/CdcChart.tsx +1 -22
- package/src/CdcChartComponent.tsx +35 -21
- package/src/_stories/Chart.CI.stories.tsx +43 -0
- package/src/_stories/Chart.DynamicSeries.stories.tsx +68 -49
- package/src/_stories/Chart.Legend.Gradient.stories.tsx +6 -0
- package/src/_stories/Chart.stories.tsx +7 -16
- package/src/_stories/_mock/bar_chart_ci_labels.json +620 -0
- package/src/_stories/_mock/barchart_labels.mock.json +612 -0
- package/src/_stories/_mock/dynamic_series_bar_config.json +1 -1
- package/src/_stories/_mock/dynamic_series_suppression_mock.json +610 -0
- package/{examples/private/line-issue.json → src/_stories/_mock/legend_groupBy_mock.json} +46 -69
- 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 +51 -41
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +19 -9
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +20 -9
- package/src/components/BarChart/components/BarChart.Vertical.tsx +48 -31
- 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 +11 -47
- package/src/components/BoxPlot/BoxPlot.tsx +2 -1
- package/src/components/DeviationBar.jsx +2 -1
- package/src/components/EditorPanel/EditorPanel.tsx +60 -24
- 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/helpers/updateFieldRankByValue.ts +4 -3
- package/src/components/EditorPanel/useEditorPermissions.ts +1 -4
- package/src/components/ForestPlot/ForestPlot.tsx +2 -2
- package/src/components/Legend/Legend.Component.tsx +69 -58
- package/src/components/Legend/Legend.Suppression.tsx +12 -22
- package/src/components/Legend/Legend.tsx +3 -1
- package/src/components/Legend/LegendGroup/LegendGroup.styles.css +40 -0
- package/src/components/Legend/LegendGroup/LegendGroup.tsx +103 -0
- package/src/components/Legend/LegendGroup/index.tsx +3 -0
- 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 +77 -119
- package/src/components/LineChart/helpers.ts +133 -56
- package/src/components/LineChart/index.tsx +125 -60
- package/src/components/LinearChart.tsx +74 -115
- 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 +4 -2
- package/src/helpers/countNumOfTicks.ts +1 -1
- package/src/helpers/dataHelpers.ts +31 -0
- package/src/helpers/sizeHelpers.ts +23 -0
- package/src/hooks/useMinMax.ts +21 -28
- package/src/hooks/useRightAxis.ts +4 -2
- package/src/hooks/useScales.ts +12 -14
- package/src/hooks/useTooltip.tsx +204 -203
- package/src/index.jsx +2 -2
- package/src/scss/main.scss +13 -6
- package/src/store/chart.actions.ts +1 -1
- package/src/types/ChartConfig.ts +7 -1
- 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
|
@@ -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
|
|
|
@@ -69,7 +80,7 @@ const BarChartStackedVertical = () => {
|
|
|
69
80
|
const xAxisTooltip = config.runtime.xAxis.label
|
|
70
81
|
? `${config.runtime.xAxis.label}: ${xAxisValue}`
|
|
71
82
|
: xAxisValue
|
|
72
|
-
const additionalColTooltip = getAdditionalColumn(hoveredBar)
|
|
83
|
+
const additionalColTooltip = getAdditionalColumn(bar.key, hoveredBar)
|
|
73
84
|
const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${yAxisValue}`
|
|
74
85
|
const tooltip = `<ul>
|
|
75
86
|
<li class="tooltip-heading"">${xAxisTooltip}</li>
|
|
@@ -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}`,
|
|
@@ -322,8 +339,8 @@ export const BarChartVertical = () => {
|
|
|
322
339
|
<Text // prettier-ignore
|
|
323
340
|
display={displayBar ? 'block' : 'none'}
|
|
324
341
|
opacity={transparentBar ? 0.5 : 1}
|
|
325
|
-
x={barX + barWidth / 2}
|
|
326
|
-
y={barY -
|
|
342
|
+
x={hasConfidenceInterval ? barX + barWidth : barX + barWidth / 2}
|
|
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
|
+
}
|
|
@@ -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
|
-
|
|
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
|
|
2
|
+
import { ChartDispatchContext } from '../../../ConfigContext'
|
|
3
3
|
import { formatNumber as formatColNumber } from '@cdc/core/helpers/cove/number'
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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 => {
|
|
@@ -200,7 +163,8 @@ export const useBarChart = () => {
|
|
|
200
163
|
return d[config.xAxis.dataKey] === xAxisDataValue && dynamicCategoryMatch
|
|
201
164
|
}) || {}
|
|
202
165
|
Object.keys(columns).forEach(colKeys => {
|
|
203
|
-
|
|
166
|
+
const colConfig = config.columns[colKeys]
|
|
167
|
+
if (series && colConfig.series && colConfig.series !== series && !colConfig.tooltips) return
|
|
204
168
|
const formattingParams = {
|
|
205
169
|
addColPrefix: config.columns[colKeys].prefix,
|
|
206
170
|
addColSuffix: config.columns[colKeys].suffix,
|
|
@@ -225,17 +189,18 @@ export const useBarChart = () => {
|
|
|
225
189
|
return additionalTooltipItems
|
|
226
190
|
}
|
|
227
191
|
|
|
228
|
-
const onMouseOverBar = (categoryValue, barKey) => {
|
|
192
|
+
const onMouseOverBar = (categoryValue, barKey, event, data) => {
|
|
229
193
|
if (config.legend.highlightOnHover && config.legend.behavior === 'highlight' && barKey) {
|
|
230
194
|
dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: [barKey] })
|
|
231
195
|
}
|
|
232
|
-
|
|
196
|
+
handleTooltipMouseOver(event, data)
|
|
233
197
|
setHoveredBar(categoryValue)
|
|
234
198
|
}
|
|
235
199
|
const onMouseLeaveBar = () => {
|
|
236
200
|
if (config.legend.highlightOnHover && config.legend.behavior === 'highlight') {
|
|
237
201
|
dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: [] })
|
|
238
202
|
}
|
|
203
|
+
handleTooltipMouseOff()
|
|
239
204
|
}
|
|
240
205
|
|
|
241
206
|
return {
|
|
@@ -255,7 +220,6 @@ export const useBarChart = () => {
|
|
|
255
220
|
barStackedSeriesKeys,
|
|
256
221
|
hasMultipleSeries,
|
|
257
222
|
applyRadius,
|
|
258
|
-
updateBars,
|
|
259
223
|
assignColorsToValues,
|
|
260
224
|
getHighlightedBarColorByValue,
|
|
261
225
|
getHighlightedBarByValue,
|
|
@@ -5,6 +5,7 @@ import ConfigContext from '../../ConfigContext'
|
|
|
5
5
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
6
6
|
import { colorPalettesChart } from '@cdc/core/data/colorPalettes'
|
|
7
7
|
import { handleTooltip, createPlots } from './helpers/index'
|
|
8
|
+
import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
|
|
8
9
|
import _ from 'lodash'
|
|
9
10
|
|
|
10
11
|
const CoveBoxPlot = ({ xScale, yScale, seriesScale }) => {
|
|
@@ -15,7 +16,7 @@ const CoveBoxPlot = ({ xScale, yScale, seriesScale }) => {
|
|
|
15
16
|
const boxWidth = xScale.bandwidth()
|
|
16
17
|
|
|
17
18
|
const bodyStyles = getComputedStyle(document.body)
|
|
18
|
-
const defaultColor =
|
|
19
|
+
const defaultColor = APP_FONT_COLOR
|
|
19
20
|
const constrainedWidth = Math.min(40, boxWidth)
|
|
20
21
|
const color_0 = _.get(colorPalettesChart, [config.palette, 0], '#000')
|
|
21
22
|
const plots = createPlots(data, config)
|
|
@@ -6,6 +6,7 @@ import { Text } from '@visx/text'
|
|
|
6
6
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
7
7
|
import useIntersectionObserver from '../hooks/useIntersectionObserver'
|
|
8
8
|
import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
|
|
9
|
+
import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
|
|
9
10
|
import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
|
|
10
11
|
|
|
11
12
|
export default function DeviationBar({ height, xScale }) {
|
|
@@ -178,7 +179,7 @@ export default function DeviationBar({ height, xScale }) {
|
|
|
178
179
|
// colors
|
|
179
180
|
const [leftColor, rightColor] = twoColorPalette[twoColor.palette]
|
|
180
181
|
const barColor = { left: leftColor, right: rightColor }
|
|
181
|
-
const fill = getContrastColor(
|
|
182
|
+
const fill = getContrastColor(APP_FONT_COLOR, barColor[barPosition])
|
|
182
183
|
|
|
183
184
|
let textProps = getTextProps(config.isLollipopChart, textFits, lollipopShapeSize, fill)
|
|
184
185
|
// tooltips
|