@cdc/chart 4.24.4 → 4.24.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cdcchart.js +39611 -36038
- package/examples/feature/annotations/index.json +542 -0
- package/examples/xaxis.json +493 -0
- package/index.html +9 -8
- package/package.json +5 -4
- package/src/CdcChart.tsx +115 -71
- package/src/_stories/Chart.stories.tsx +26 -171
- package/src/_stories/ChartAnnotation.stories.tsx +32 -0
- package/src/_stories/_mock/annotation_category_mock.json +473 -0
- package/src/_stories/_mock/annotation_date-linear_mock.json +530 -0
- package/src/_stories/_mock/annotation_date-time_mock.json +530 -0
- package/src/_stories/_mock/bar-chart-suppressed.json +474 -0
- package/src/_stories/_mock/line_chart_two_points_new_chart.json +128 -0
- package/src/_stories/_mock/line_chart_two_points_regression_test.json +127 -0
- package/src/_stories/_mock/lollipop.json +171 -0
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +31 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +154 -0
- package/src/components/Annotations/components/AnnotationDropdown.styles.css +14 -0
- package/src/components/Annotations/components/AnnotationDropdown.tsx +72 -0
- package/src/components/Annotations/components/AnnotationList.styles.css +45 -0
- package/src/components/Annotations/components/AnnotationList.tsx +42 -0
- package/src/components/Annotations/components/findNearestDatum.ts +138 -0
- package/src/components/Annotations/components/helpers/index.tsx +46 -0
- package/src/components/Annotations/index.tsx +13 -0
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +1 -1
- package/src/components/AreaChart/components/AreaChart.jsx +2 -2
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +78 -71
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +1 -2
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +11 -11
- package/src/components/BarChart/components/BarChart.Vertical.tsx +100 -87
- package/src/components/BarChart/helpers/index.ts +102 -0
- package/src/components/DeviationBar.jsx +4 -2
- package/src/components/EditorPanel/EditorPanel.tsx +435 -613
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +306 -0
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +135 -7
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +2 -3
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -5
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +3 -2
- package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
- package/src/components/EditorPanel/components/panels.scss +4 -0
- package/src/components/EditorPanel/editor-panel.scss +19 -0
- package/src/components/EditorPanel/useEditorPermissions.js +23 -3
- package/src/components/Legend/Legend.Component.tsx +66 -15
- package/src/components/Legend/helpers/createFormatLabels.tsx +1 -1
- package/src/components/Legend/helpers/index.ts +5 -0
- package/src/components/LineChart/LineChartProps.ts +16 -6
- package/src/components/LineChart/components/LineChart.Circle.tsx +22 -11
- package/src/components/LineChart/helpers.ts +148 -10
- package/src/components/LineChart/index.tsx +71 -44
- package/src/components/LinearChart.jsx +184 -125
- package/src/components/PairedBarChart.jsx +9 -9
- package/src/components/PieChart/PieChart.tsx +4 -4
- package/src/components/Sankey/index.tsx +73 -20
- package/src/components/ScatterPlot/ScatterPlot.jsx +22 -8
- package/src/components/ZoomBrush.tsx +120 -55
- package/src/data/initial-state.js +14 -6
- package/src/helpers/handleChartTabbing.ts +8 -0
- package/src/helpers/isConvertLineToBarGraph.ts +4 -0
- package/src/hooks/{useBarChart.js → useBarChart.ts} +9 -22
- package/src/hooks/useColorScale.ts +1 -1
- package/src/hooks/useMinMax.ts +29 -5
- package/src/hooks/useScales.ts +48 -26
- package/src/hooks/useTooltip.tsx +62 -15
- package/src/scss/main.scss +69 -12
- package/src/types/ChartConfig.ts +53 -16
- package/src/types/ChartContext.ts +13 -0
- package/tests-examples/helpers/testZeroValue.test.ts +30 -0
- package/LICENSE +0 -201
- package/src/_stories/ChartLine.preliminary.tsx +0 -19
- package/src/_stories/ChartSuppress.stories.tsx +0 -19
- package/src/_stories/_mock/suppress_mock.json +0 -911
- package/src/helpers/computeMarginBottom.ts +0 -56
- package/src/helpers/filterData.ts +0 -18
- package/src/helpers/tests/computeMarginBottom.test.ts +0 -21
- /package/src/hooks/{useLegendClasses.js → useLegendClasses.ts} +0 -0
- /package/src/hooks/{useReduceData.js → useReduceData.ts} +0 -0
|
@@ -1,33 +1,36 @@
|
|
|
1
1
|
import React, { useContext, useState } from 'react'
|
|
2
|
+
// Local contexts
|
|
2
3
|
import ConfigContext from '../../../ConfigContext'
|
|
3
|
-
import { type
|
|
4
|
+
import BarChartContext, { type BarChartContextValues } from './context'
|
|
5
|
+
// Local hooks
|
|
4
6
|
import { useBarChart } from '../../../hooks/useBarChart'
|
|
7
|
+
import { useHighlightedBars } from '../../../hooks/useHighlightedBars'
|
|
8
|
+
import { getBarConfig, testZeroValue } from '../helpers'
|
|
9
|
+
import { isConvertLineToBarGraph } from '../../../helpers/isConvertLineToBarGraph'
|
|
10
|
+
// VisX library imports
|
|
5
11
|
import { Group } from '@visx/group'
|
|
6
12
|
import { Text } from '@visx/text'
|
|
7
13
|
import { BarGroup } from '@visx/shape'
|
|
8
|
-
|
|
9
|
-
import
|
|
10
|
-
|
|
14
|
+
// Local components
|
|
15
|
+
import Regions from '../../Regions'
|
|
16
|
+
// CDC core components and helpers
|
|
11
17
|
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
12
|
-
|
|
13
18
|
import createBarElement from '@cdc/core/components/createBarElement'
|
|
14
|
-
|
|
15
|
-
// third party
|
|
19
|
+
// Third party libraries
|
|
16
20
|
import chroma from 'chroma-js'
|
|
17
|
-
|
|
21
|
+
// Types
|
|
22
|
+
import { type ChartContext } from '../../../types/ChartContext'
|
|
18
23
|
|
|
19
24
|
export const BarChartVertical = () => {
|
|
20
25
|
const { xScale, yScale, xMax, yMax, seriesScale } = useContext<BarChartContextValues>(BarChartContext)
|
|
21
26
|
|
|
22
27
|
const [barWidth, setBarWidth] = useState(0)
|
|
23
28
|
const [totalBarsInGroup, setTotalBarsInGroup] = useState(0)
|
|
24
|
-
|
|
25
29
|
// prettier-ignore
|
|
26
30
|
const {
|
|
27
|
-
|
|
31
|
+
// prettier-ignore
|
|
28
32
|
assignColorsToValues,
|
|
29
33
|
barBorderWidth,
|
|
30
|
-
generateIconSize,
|
|
31
34
|
getAdditionalColumn,
|
|
32
35
|
getHighlightedBarByValue,
|
|
33
36
|
getHighlightedBarColorByValue,
|
|
@@ -39,37 +42,23 @@ export const BarChartVertical = () => {
|
|
|
39
42
|
} = useBarChart()
|
|
40
43
|
|
|
41
44
|
// prettier-ignore
|
|
42
|
-
const {
|
|
43
|
-
colorScale,
|
|
44
|
-
config,
|
|
45
|
-
dashboardConfig,
|
|
46
|
-
formatDate,
|
|
47
|
-
formatNumber,
|
|
48
|
-
getXAxisData,
|
|
49
|
-
getYAxisData,
|
|
50
|
-
isNumber,
|
|
51
|
-
parseDate,
|
|
52
|
-
seriesHighlight,
|
|
53
|
-
setSharedFilter,
|
|
54
|
-
transformedData,
|
|
55
|
-
} = useContext<ChartContext>(ConfigContext)
|
|
56
|
-
|
|
45
|
+
const { colorScale, config, dashboardConfig, tableData, formatDate, formatNumber, getXAxisData, getYAxisData, isNumber, parseDate, seriesHighlight, setSharedFilter, transformedData, brushConfig, getTextWidth } = useContext<ChartContext>(ConfigContext)
|
|
57
46
|
const { HighLightedBarUtils } = useHighlightedBars(config)
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
return icon
|
|
47
|
+
let data = transformedData
|
|
48
|
+
// check if user add suppression
|
|
49
|
+
const isSuppressionActive = config.preliminaryData.some(pd => pd.value && pd.type === 'suppression')
|
|
50
|
+
// if suppression active use table data (filtere | excluded) but non cleaned
|
|
51
|
+
if (isSuppressionActive) {
|
|
52
|
+
data = tableData
|
|
53
|
+
}
|
|
54
|
+
// if brush active use brush data (filtered|excluded) not cleaned
|
|
55
|
+
if (brushConfig.data.length) {
|
|
56
|
+
data = brushConfig.data
|
|
69
57
|
}
|
|
58
|
+
|
|
70
59
|
return (
|
|
71
60
|
config.visualizationSubType !== 'stacked' &&
|
|
72
|
-
(config.visualizationType === 'Bar' || config.visualizationType === 'Combo') &&
|
|
61
|
+
(config.visualizationType === 'Bar' || config.visualizationType === 'Combo' || isConvertLineToBarGraph(config.visualizationType, data, config.allowLineToBarGraph)) &&
|
|
73
62
|
config.orientation === 'vertical' && (
|
|
74
63
|
<Group>
|
|
75
64
|
<BarGroup
|
|
@@ -92,30 +81,24 @@ export const BarChartVertical = () => {
|
|
|
92
81
|
<Group className={`bar-group-${barGroup.index}-${barGroup.x0}--${index} ${config.orientation}`} key={`bar-group-${barGroup.index}-${barGroup.x0}--${index}`} id={`bar-group-${barGroup.index}-${barGroup.x0}--${index}`} left={barGroup.x0}>
|
|
93
82
|
{barGroup.bars.map((bar, index) => {
|
|
94
83
|
const scaleVal = config.useLogScale ? 0.1 : 0
|
|
95
|
-
const suppresedBarHeight = 20
|
|
96
84
|
let highlightedBarValues = config.highlightedBarValues.map(item => item.value).filter(item => item !== ('' || undefined))
|
|
97
85
|
highlightedBarValues = config.xAxis.type === 'date' ? HighLightedBarUtils.formatDates(highlightedBarValues) : highlightedBarValues
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
let barHeightBase = Math.abs(yScale(bar.value) - yScale(scaleVal))
|
|
101
|
-
let barYBase = bar.value >= 0 && isNumber(bar.value) ? bar.y : yScale(0)
|
|
102
|
-
const supprssedBarY = bar.value >= 0 && isNumber(bar.value) ? yScale(scaleVal) - suppresedBarHeight : yScale(0)
|
|
103
|
-
const barY = config.suppressedData.some(d => bar.key === d.column && String(bar.value) === String(d.value)) ? supprssedBarY : barYBase
|
|
104
|
-
|
|
105
|
-
let barGroupWidth = seriesScale.range()[1]
|
|
86
|
+
const transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
|
|
87
|
+
const displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
|
|
106
88
|
|
|
107
|
-
let
|
|
89
|
+
let barGroupWidth = seriesScale.range()[1] - seriesScale.range()[0]
|
|
90
|
+
const defaultBarHeight = Math.abs(yScale(bar.value) - yScale(scaleVal))
|
|
91
|
+
const defaultBarY = bar.value >= 0 && isNumber(bar.value) ? bar.y : yScale(0)
|
|
92
|
+
let barWidth = config.isLollipopChart ? lollipopBarWidth : seriesScale.bandwidth()
|
|
108
93
|
let barX = bar.x + (config.isLollipopChart ? (barGroupWidth / barGroup.bars.length - lollipopBarWidth) / 2 : 0) - (config.xAxis.type === 'date-time' ? barGroupWidth / 2 : 0)
|
|
109
94
|
setBarWidth(barWidth)
|
|
110
95
|
setTotalBarsInGroup(barGroup.bars.length)
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
let xAxisValue = config.runtime[section].type === 'date' ? formatDate(parseDate(data[barGroup.index][config.runtime.originalXAxis.dataKey])) : data[barGroup.index][config.runtime.originalXAxis.dataKey]
|
|
96
|
+
const yAxisValue = formatNumber(/[a-zA-Z]/.test(String(bar.value)) ? '' : bar.value, 'left')
|
|
97
|
+
const xAxisValue = config.runtime[section].type === 'date' ? formatDate(parseDate(data[barGroup.index][config.runtime.originalXAxis.dataKey])) : data[barGroup.index][config.runtime.originalXAxis.dataKey]
|
|
114
98
|
|
|
115
99
|
// create new Index for bars with negative values
|
|
116
100
|
const newIndex = bar.value < 0 ? -1 : index
|
|
117
101
|
// tooltips
|
|
118
|
-
|
|
119
102
|
const additionalColTooltip = getAdditionalColumn(bar.key, data[barGroup.index][config.runtime.originalXAxis.dataKey])
|
|
120
103
|
let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
|
|
121
104
|
const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${yAxisValue}`
|
|
@@ -138,10 +121,13 @@ export const BarChartVertical = () => {
|
|
|
138
121
|
const highlightedBar = getHighlightedBarByValue(xAxisValue)
|
|
139
122
|
const borderColor = isHighlightedBar ? highlightedBarColor : config.barHasBorder === 'true' ? '#000' : 'transparent'
|
|
140
123
|
const borderWidth = isHighlightedBar ? highlightedBar.borderWidth : config.isLollipopChart ? 0 : config.barHasBorder === 'true' ? barBorderWidth : 0
|
|
141
|
-
const barValueLabel = config.suppressedData.some(d => bar.key === d.column && bar.value === d.value) ? '' : yAxisValue
|
|
142
|
-
let barHeight = config.suppressedData.some(d => bar.key === d.column && String(bar.value) === String(d.value)) ? suppresedBarHeight : barHeightBase
|
|
143
|
-
const displaylollipopShape = config.suppressedData.some(d => bar.key === d.column && bar.value === d.value) ? 'none' : 'block'
|
|
144
124
|
|
|
125
|
+
const { barHeight, isSuppressed, getBarY, getAbsentDataLabel } = getBarConfig({ bar, defaultBarHeight, config, isNumber, getTextWidth, barWidth, isVertical: true, yAxisValue })
|
|
126
|
+
|
|
127
|
+
const absentDataLabel = getAbsentDataLabel(yAxisValue)
|
|
128
|
+
const barDefaultLabel = isSuppressed || !config.labels ? '' : yAxisValue
|
|
129
|
+
const barY = getBarY(defaultBarY, yScale(scaleVal))
|
|
130
|
+
const displaylollipopShape = testZeroValue(bar.value) ? 'none' : 'block'
|
|
145
131
|
const getBarBackgroundColor = (barColor: string, filteredOutColor?: string): string => {
|
|
146
132
|
let _barColor = barColor
|
|
147
133
|
let _filteredOutColor = filteredOutColor || '#f2f2f2'
|
|
@@ -154,18 +140,20 @@ export const BarChartVertical = () => {
|
|
|
154
140
|
if (dashboardConfig && dashboardConfig.dashboard.sharedFilters?.length !== 0) {
|
|
155
141
|
const { sharedFilters } = dashboardConfig.dashboard
|
|
156
142
|
|
|
157
|
-
_barColor = sharedFilters
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
143
|
+
_barColor = sharedFilters
|
|
144
|
+
? sharedFilters.map(_sharedFilter => {
|
|
145
|
+
if (_sharedFilter.setBy === config.uid) {
|
|
146
|
+
// If the current filter is the reset filter item.
|
|
147
|
+
if (_sharedFilter.resetLabel === _sharedFilter.active) return colorScale(config.runtime.seriesLabels[bar.key])
|
|
148
|
+
// If the current filter is the bars
|
|
149
|
+
if (_sharedFilter.active === transformedData[barGroup.index][config.xAxis.dataKey]) return colorScale(config.runtime.seriesLabels[bar.key])
|
|
150
|
+
return _filteredOutColor
|
|
151
|
+
} else {
|
|
152
|
+
// If the setBy isn't the config.uid return the original barColor
|
|
153
|
+
return colorScale(config.runtime.seriesLabels[bar.key])
|
|
154
|
+
}
|
|
155
|
+
})[0]
|
|
156
|
+
: colorScale(config.runtime.seriesLabels[bar.key])
|
|
169
157
|
|
|
170
158
|
if (isRegularLollipopColor) _barColor = barColor
|
|
171
159
|
if (isTwoToneLollipopColor) _barColor = chroma(barColor).brighten(1)
|
|
@@ -214,34 +202,59 @@ export const BarChartVertical = () => {
|
|
|
214
202
|
cursor: dashboardConfig ? 'pointer' : 'default'
|
|
215
203
|
}
|
|
216
204
|
})}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
205
|
+
{config.preliminaryData.map((pd, index) => {
|
|
206
|
+
// check if user selected column
|
|
207
|
+
const selectedSuppressionColumn = !pd.column || pd.column === bar.key
|
|
208
|
+
// compare entered suppressed value with data value
|
|
209
|
+
const isValueMatch = String(pd.value) === String(bar.value) && pd.value !== ''
|
|
210
|
+
const isSuppressed = isValueMatch && selectedSuppressionColumn
|
|
211
|
+
|
|
212
|
+
if (!isSuppressed || barWidth < 10 || !config.general.showSuppressedSymbol || pd.hideBarSymbol) {
|
|
213
|
+
return
|
|
214
|
+
}
|
|
215
|
+
const hasAsterisk = String(pd.symbol).includes('Asterisk')
|
|
216
|
+
const yPadding = hasAsterisk ? -5 : -8
|
|
217
|
+
const verticalAnchor = hasAsterisk ? 'middle' : 'end'
|
|
218
|
+
const iconSize = pd.symbol === 'Asterisk' ? barWidth * 1.2 : pd.symbol === 'Double Asterisk' ? barWidth : barWidth / 1.5
|
|
219
|
+
|
|
220
|
+
return (
|
|
221
|
+
<Text // prettier-ignore
|
|
222
|
+
key={index}
|
|
223
|
+
dy={yPadding}
|
|
224
|
+
display={displayBar ? 'block' : 'none'}
|
|
225
|
+
opacity={transparentBar ? 0.5 : 1}
|
|
226
|
+
x={barX + barWidth / 2}
|
|
227
|
+
y={barY}
|
|
228
|
+
verticalAnchor={verticalAnchor}
|
|
229
|
+
fill={labelColor}
|
|
230
|
+
textAnchor='middle'
|
|
231
|
+
fontSize={`${iconSize}px`}
|
|
232
|
+
>
|
|
233
|
+
{pd.iconCode}
|
|
234
|
+
</Text>
|
|
235
|
+
)
|
|
236
|
+
})}
|
|
237
|
+
|
|
238
|
+
<Text // prettier-ignore
|
|
222
239
|
display={displayBar ? 'block' : 'none'}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
bar[config.xAxis.dataKey] = xAxisValue
|
|
229
|
-
setSharedFilter(config.uid, bar)
|
|
230
|
-
}
|
|
231
|
-
}}
|
|
240
|
+
opacity={transparentBar ? 0.5 : 1}
|
|
241
|
+
x={barX + barWidth / 2}
|
|
242
|
+
y={barY - 5}
|
|
243
|
+
fill={labelColor}
|
|
244
|
+
textAnchor='middle'
|
|
232
245
|
>
|
|
233
|
-
{
|
|
234
|
-
</
|
|
235
|
-
|
|
246
|
+
{testZeroValue(bar.value) ? '' : barDefaultLabel}
|
|
247
|
+
</Text>
|
|
236
248
|
<Text // prettier-ignore
|
|
237
|
-
display={
|
|
249
|
+
display={displayBar ? 'block' : 'none'}
|
|
238
250
|
opacity={transparentBar ? 0.5 : 1}
|
|
239
251
|
x={barX + barWidth / 2}
|
|
240
252
|
y={barY - 5}
|
|
241
253
|
fill={labelColor}
|
|
242
254
|
textAnchor='middle'
|
|
255
|
+
fontSize={config.isLollipopChart ? null : barWidth / 2}
|
|
243
256
|
>
|
|
244
|
-
{
|
|
257
|
+
{absentDataLabel}
|
|
245
258
|
</Text>
|
|
246
259
|
|
|
247
260
|
{config.isLollipopChart && config.lollipopShape === 'circle' && (
|
|
@@ -288,7 +301,7 @@ export const BarChartVertical = () => {
|
|
|
288
301
|
let upperPos
|
|
289
302
|
let lowerPos
|
|
290
303
|
let tickWidth = 5
|
|
291
|
-
xPos = xScale(getXAxisData(d)) + (config.xAxis.type !== 'date
|
|
304
|
+
xPos = xScale(getXAxisData(d)) + (config.xAxis.type !== 'date-time' ? seriesScale.range()[1] / 2 : 0)
|
|
292
305
|
upperPos = yScale(getYAxisData(d, config.confidenceKeys.lower))
|
|
293
306
|
lowerPos = yScale(getYAxisData(d, config.confidenceKeys.upper))
|
|
294
307
|
return (
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
// Define an interface for the function's parameter
|
|
2
|
+
interface BarConfigProps {
|
|
3
|
+
defaultBarWidth?: number
|
|
4
|
+
defaultBarHeight?: number
|
|
5
|
+
bar?: { [key: string]: any }
|
|
6
|
+
isNumber?: Function
|
|
7
|
+
config: { [key: string]: any }
|
|
8
|
+
getTextWidth: Function
|
|
9
|
+
barWidth: number
|
|
10
|
+
isVertical: boolean
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Function to create bar width based on suppression status and missing data label
|
|
14
|
+
export const getBarConfig = ({ bar, defaultBarHeight, defaultBarWidth, config, isNumber, getTextWidth, barWidth, isVertical }: BarConfigProps) => {
|
|
15
|
+
const heightMini = 3 /// height of small bars aka suppressed/NA/Zero valued
|
|
16
|
+
let barHeight = defaultBarHeight
|
|
17
|
+
|
|
18
|
+
let barWidthHorizontal = defaultBarWidth
|
|
19
|
+
|
|
20
|
+
let barLabel = ''
|
|
21
|
+
let isSuppressed = false
|
|
22
|
+
let showMissingDataLabel = false
|
|
23
|
+
let showZeroValueDataLabel = false
|
|
24
|
+
const showSuppressedSymbol = config.general.showSuppressedSymbol
|
|
25
|
+
|
|
26
|
+
config.preliminaryData.forEach(pd => {
|
|
27
|
+
const hasColumn = !pd.column || pd.column === bar.key
|
|
28
|
+
if (hasColumn && pd.type === 'suppression' && pd.value && String(pd.value) === String(bar.value)) {
|
|
29
|
+
if (!pd.hideBarSymbol && showSuppressedSymbol) {
|
|
30
|
+
barHeight = barWidth > 10 ? heightMini : 0
|
|
31
|
+
barWidthHorizontal = heightMini
|
|
32
|
+
isSuppressed = true
|
|
33
|
+
} else {
|
|
34
|
+
barHeight = 0
|
|
35
|
+
barWidthHorizontal = 0
|
|
36
|
+
isSuppressed = true
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
// Handle undefined, null, or non-calculable bar.value
|
|
42
|
+
if (!isSuppressed && !isNumber(bar.value) && config.general.showMissingDataLabel) {
|
|
43
|
+
const labelWidth = getTextWidth(barLabel, `normal ${barWidth / 2}px sans-serif`)
|
|
44
|
+
const labelFits = labelWidth < barWidth && barWidth > 10
|
|
45
|
+
showMissingDataLabel = true
|
|
46
|
+
barHeight = labelFits ? heightMini : 0
|
|
47
|
+
barWidthHorizontal = heightMini
|
|
48
|
+
}
|
|
49
|
+
// handle zero values
|
|
50
|
+
if (!isSuppressed && String(bar.value) === '0' && config.general.showZeroValueDataLabel) {
|
|
51
|
+
const labelWidth = getTextWidth(barLabel, `normal ${barWidth / 2}px sans-serif`)
|
|
52
|
+
const labelFits = labelWidth < barWidth && barWidth > 10
|
|
53
|
+
barHeight = config.isLollipopChart ? heightMini * 2 : !config.isLollipopChart && labelFits ? heightMini : 0
|
|
54
|
+
barWidthHorizontal = heightMini
|
|
55
|
+
showZeroValueDataLabel = true
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const getBarY = (defaultBarY, yScale) => {
|
|
59
|
+
// calculate Y position of small bars (suppressed,N/A,Zero valued) bars
|
|
60
|
+
if (isSuppressed || showMissingDataLabel || showZeroValueDataLabel) {
|
|
61
|
+
if (config.isLollipopChart) {
|
|
62
|
+
return yScale - heightMini * 2
|
|
63
|
+
} else {
|
|
64
|
+
return yScale - heightMini
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return defaultBarY
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Function to determine the label for a bar in a bar chart vertical/Horizontal
|
|
71
|
+
const getAbsentDataLabel = yAxisValue => {
|
|
72
|
+
// Initialize label with the yAxisValue
|
|
73
|
+
let label = ''
|
|
74
|
+
// Check if the label is exactly '0' and if so, hide it
|
|
75
|
+
if (String(yAxisValue) === '0') label = ''
|
|
76
|
+
// Check if the bar is marked as suppressed. If so, do not show any label.
|
|
77
|
+
if (isSuppressed) label = ''
|
|
78
|
+
// If the config is set to show a label for missing data, display 'N/A'
|
|
79
|
+
if (showMissingDataLabel) label = 'N/A'
|
|
80
|
+
// If the config is set to specifically show zero values, set the label to '0'
|
|
81
|
+
if (showZeroValueDataLabel) label = '0'
|
|
82
|
+
|
|
83
|
+
// determine label width in pixels & check if it fits to the bar width
|
|
84
|
+
const labelWidth = getTextWidth(barLabel, `normal ${barWidth / 2}px sans-serif`)
|
|
85
|
+
const labelFits = labelWidth < barWidth && barWidth > 10
|
|
86
|
+
if (config.isLollipopChart) {
|
|
87
|
+
return label
|
|
88
|
+
} else {
|
|
89
|
+
return labelFits && isVertical ? label : !isVertical ? label : ''
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return { barWidthHorizontal, barHeight, isSuppressed, showMissingDataLabel, showZeroValueDataLabel, getBarY, getAbsentDataLabel }
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export const testZeroValue = value => {
|
|
97
|
+
if (value === undefined || value === null) {
|
|
98
|
+
return
|
|
99
|
+
}
|
|
100
|
+
const regex = /^0(\.0)?$/
|
|
101
|
+
return regex.test(value.toString())
|
|
102
|
+
}
|
|
@@ -82,7 +82,8 @@ export default function DeviationBar({ height, xScale }) {
|
|
|
82
82
|
useEffect(() => {
|
|
83
83
|
const handleResize = () => {
|
|
84
84
|
setWindowWidth(window.innerWidth)
|
|
85
|
-
barRefs.current
|
|
85
|
+
barRefs.current?.forEach(bar => {
|
|
86
|
+
if (!bar || !bar.style) return
|
|
86
87
|
bar.style.transition = 'none'
|
|
87
88
|
bar.style.transform = 'translate(0) scale(1)'
|
|
88
89
|
})
|
|
@@ -104,7 +105,8 @@ export default function DeviationBar({ height, xScale }) {
|
|
|
104
105
|
}, [entry?.isIntersecting, config.animate]) // eslint-disable-line
|
|
105
106
|
|
|
106
107
|
useEffect(() => {
|
|
107
|
-
barRefs.current
|
|
108
|
+
barRefs.current?.forEach((bar, i) => {
|
|
109
|
+
if (!bar || !bar.style) return
|
|
108
110
|
if (config.animate) {
|
|
109
111
|
const normalizedTarget = (target / maxVal) * 100
|
|
110
112
|
bar.style.opacity = '0'
|