@cdc/chart 4.23.3 → 4.23.5
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 +52543 -50830
- package/examples/feature/__data__/area-chart.json +56 -0
- package/examples/{planet-example-data.json → feature/__data__/planet-example-data.json} +3 -8
- package/examples/feature/__data__/planet-logaritmic-data.json +56 -0
- package/examples/feature/area/area-chart-category.json +240 -0
- package/examples/{area-chart.json → feature/area/area-chart-date.json} +70 -13
- package/examples/feature/bar/example-bar-chart.json +558 -0
- package/examples/{horizontal-chart-max-increase.json → feature/bar/horizontal-chart-max-increase.json} +10 -4
- package/examples/{horizontal-chart.json → feature/bar/horizontal-chart.json} +10 -4
- package/examples/{horizontal-stacked-bar-chart.json → feature/bar/horizontal-stacked-bar-chart.json} +7 -3
- package/examples/{planet-chart-horizontal-example-config.json → feature/bar/planet-chart-horizontal-example-config.json} +8 -3
- package/examples/feature/bar/planet-chart-logaritmic-config.json +170 -0
- package/examples/{planet-example-config.json → feature/bar/planet-example-config.json} +2 -2
- package/examples/{box-plot.json → feature/boxplot/boxplot.json} +7 -7
- package/examples/feature/boxplot/testing.csv +38 -0
- package/examples/feature/boxplot/valid-boxplot.csv +17 -0
- package/examples/feature/combo/combochart-categories_are_numbers .json +18 -0
- package/examples/{planet-combo-example-config.json → feature/combo/planet-combo-example-config.json} +1 -1
- package/examples/{planet-deviation-config.json → feature/deviation/planet-deviation-config.json} +2 -2
- package/examples/{planet-deviation-data.json → feature/deviation/planet-deviation-data.json} +9 -9
- package/examples/feature/filters/filter-testing.json +212 -0
- package/examples/feature/forecasting/case_date_example.csv +130 -0
- package/examples/feature/forecasting/effective_reproduction.json +202 -0
- package/examples/feature/forecasting/r_data.csv +130 -0
- package/examples/feature/forecasting/random_data.csv +366 -0
- package/examples/feature/line/line-chart.json +124 -0
- package/examples/{paired-bar-example.json → feature/paired-bar/paired-bar-example.json} +10 -4
- package/examples/{planet-pie-example-config.json → feature/pie/planet-pie-example-config.json} +2 -2
- package/examples/{scatterplot.json → feature/scatterplot/scatterplot.json} +1 -1
- package/examples/feature/test-highlight/test-highlight-2.json +789 -0
- package/examples/feature/test-highlight/test-highlight-vertical.json +561 -0
- package/examples/feature/test-highlight/test-highlight.json +100 -0
- package/examples/{case-rate-example-config.json → feature/tests-case-rate/case-rate-example-config.json} +2 -2
- package/examples/{covid-confidence-example-config.json → feature/tests-covid/covid-confidence-example-config.json} +8 -3
- package/examples/{covid-example-config.json → feature/tests-covid/covid-example-config.json} +7 -3
- package/examples/{cutoff-example-config.json → feature/tests-cutoff/cutoff-example-config.json} +7 -3
- package/examples/{date-exclusions-config.json → feature/tests-date-exclusions/date-exclusions-config.json} +2 -2
- package/examples/{example-bar-chart-nonnumeric.json → feature/tests-non-numerics/example-bar-chart-nonnumeric.json} +1 -1
- package/examples/{planet-pie-example-config-nonnumeric.json → feature/tests-non-numerics/planet-pie-example-config-nonnumeric.json} +2 -2
- package/examples/{sparkline-chart-nonnumeric.json → feature/tests-non-numerics/sparkline-chart-nonnumeric.json} +1 -1
- package/examples/{stacked-vertical-bar-example-nonnumerics.json → feature/tests-non-numerics/stacked-vertical-bar-example-nonnumerics.json} +1 -2
- package/examples/gallery/bar-chart-horizontal/horizontal-highlight.json +345 -0
- package/examples/gallery/bar-chart-vertical/combo-line-chart.json +145 -7
- package/examples/gallery/paired-bar/paired-bar-chart.json +1 -0
- package/index.html +73 -49
- package/package.json +2 -2
- package/src/CdcChart.jsx +405 -40
- package/src/components/AreaChart.jsx +122 -80
- package/src/components/BarChart.jsx +126 -49
- package/src/components/BoxPlot.jsx +28 -20
- package/src/components/DataTable.jsx +7 -6
- package/src/components/DeviationBar.jsx +34 -34
- package/src/components/EditorPanel.jsx +1332 -352
- package/src/components/Legend.jsx +40 -4
- package/src/components/LineChart.jsx +10 -23
- package/src/components/LinearChart.jsx +133 -286
- package/src/components/PairedBarChart.jsx +6 -6
- package/src/components/PieChart.jsx +2 -4
- package/src/components/SparkLine.jsx +6 -42
- package/src/data/initial-state.js +23 -4
- package/src/hooks/useHighlightedBars.js +154 -0
- package/src/hooks/useMinMax.js +92 -0
- package/src/hooks/useReduceData.js +31 -57
- package/src/hooks/useScales.js +202 -0
- package/src/index.jsx +2 -1
- package/src/scss/editor-panel.scss +15 -0
- package/src/scss/main.scss +8 -6
- package/examples/box-plot.csv +0 -5
- package/examples/dynamic-legends.json +0 -125
- package/examples/example-bar-chart.json +0 -36
- package/examples/line-chart.json +0 -34
- package/examples/temp-example-config.json +0 -64
- package/examples/temp-example-data.json +0 -130
- package/src/components/Filters.jsx +0 -126
- /package/examples/{age-adjusted-rates.json → feature/__data__/age-adjusted-rates.json} +0 -0
- /package/examples/{new-data.csv → feature/__data__/new-data.csv} +0 -0
- /package/examples/{planet-example-data-max-increase.json → feature/__data__/planet-example-data-max-increase.json} +0 -0
- /package/examples/{Barchart_with_negative.json → feature/bar/Barchart_with_negative.json} +0 -0
- /package/examples/{stacked-vertical-bar-example-negative.json → feature/bar/stacked-vertical-bar-example-negative.json} +0 -0
- /package/examples/{stacked-vertical-bar-example.json → feature/bar/stacked-vertical-bar-example.json} +0 -0
- /package/examples/{box-plot-data.json → feature/boxplot/box-plot-data.json} +0 -0
- /package/examples/{newdata.json → feature/boxplot/boxplot-data.json} +0 -0
- /package/examples/{line-chart-max-increase.json → feature/line/line-chart-max-increase.json} +0 -0
- /package/examples/{paired-bar-data.json → feature/paired-bar/paired-bar-data.json} +0 -0
- /package/examples/{paired-bar-formatted.json → feature/paired-bar/paired-bar-formatted.json} +0 -0
- /package/examples/{scatterplot-continuous.csv → feature/scatterplot/scatterplot-continuous.csv} +0 -0
- /package/examples/{example-sparkline.json → feature/sparkline/example-sparkline.json} +0 -0
- /package/examples/{big-small-test-bar.json → feature/tests-big-small/big-small-test-bar.json} +0 -0
- /package/examples/{big-small-test-line.json → feature/tests-big-small/big-small-test-line.json} +0 -0
- /package/examples/{big-small-test-negative.json → feature/tests-big-small/big-small-test-negative.json} +0 -0
- /package/examples/{case-rate-example-data.json → feature/tests-case-rate/case-rate-example-data.json} +0 -0
- /package/examples/{covid-example-data-confidence.json → feature/tests-covid/covid-example-data-confidence.json} +0 -0
- /package/examples/{covid-example-data.json → feature/tests-covid/covid-example-data.json} +0 -0
- /package/examples/{cutoff-example-data.json → feature/tests-cutoff/cutoff-example-data.json} +0 -0
- /package/examples/{date-exclusions-data.json → feature/tests-date-exclusions/date-exclusions-data.json} +0 -0
- /package/examples/{example-combo-bar-nonnumeric.json → feature/tests-non-numerics/example-combo-bar-nonnumeric.json} +0 -0
- /package/examples/{line-chart-nonnumeric.json → feature/tests-non-numerics/line-chart-nonnumeric.json} +0 -0
- /package/examples/{planet-example-data-nonnumeric.json → feature/tests-non-numerics/planet-example-data-nonnumeric.json} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useContext,
|
|
1
|
+
import React, { useContext, useEffect, useState } from 'react'
|
|
2
2
|
|
|
3
3
|
// cdc
|
|
4
4
|
import ConfigContext from '../ConfigContext'
|
|
@@ -6,26 +6,29 @@ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
|
6
6
|
import { colorPalettesChart } from '@cdc/core/data/colorPalettes'
|
|
7
7
|
|
|
8
8
|
// visx & d3
|
|
9
|
+
import * as allCurves from '@visx/curve'
|
|
9
10
|
import { AreaClosed, LinePath, Bar } from '@visx/shape'
|
|
10
11
|
import { Group } from '@visx/group'
|
|
11
|
-
import
|
|
12
|
-
import { useTooltip, useTooltipInPortal, defaultStyles } from '@visx/tooltip'
|
|
12
|
+
import { useTooltip, useTooltipInPortal, defaultStyles, Tooltip } from '@visx/tooltip'
|
|
13
13
|
import { localPoint } from '@visx/event'
|
|
14
14
|
import { bisector } from 'd3-array'
|
|
15
15
|
|
|
16
|
-
const CoveAreaChart = ({ xScale, yScale, yMax, xMax }) => {
|
|
16
|
+
const CoveAreaChart = ({ xScale, yScale, yMax, xMax, chartRef }) => {
|
|
17
17
|
// enable various console logs in the file
|
|
18
18
|
const DEBUG = false
|
|
19
|
+
const [chartPosition, setChartPosition] = useState(null)
|
|
20
|
+
|
|
21
|
+
useEffect(() => {
|
|
22
|
+
setChartPosition(chartRef.current.getBoundingClientRect())
|
|
23
|
+
}, [chartRef])
|
|
19
24
|
|
|
20
25
|
// import data from context
|
|
21
|
-
const { transformedData: data, config, handleLineType, parseDate, formatDate, formatNumber, seriesHighlight } = useContext(ConfigContext)
|
|
26
|
+
const { transformedData: data, config, handleLineType, parseDate, formatDate, formatNumber, seriesHighlight, colorScale } = useContext(ConfigContext)
|
|
27
|
+
const tooltip_id = `cdc-open-viz-tooltip-${config.runtime.uniqueId}`
|
|
22
28
|
|
|
23
29
|
// import tooltip helpers
|
|
24
30
|
const { tooltipData, showTooltip } = useTooltip()
|
|
25
31
|
|
|
26
|
-
// used for offset on tooltip hover
|
|
27
|
-
let isEditor = window.location.href.includes('editor=true')
|
|
28
|
-
|
|
29
32
|
// here we're inside of the svg,
|
|
30
33
|
// it appears we need to use TooltipInPortal.
|
|
31
34
|
const { TooltipInPortal } = useTooltipInPortal({
|
|
@@ -36,20 +39,21 @@ const CoveAreaChart = ({ xScale, yScale, yMax, xMax }) => {
|
|
|
36
39
|
|
|
37
40
|
// Draw transparent bars over the chart to get tooltip data
|
|
38
41
|
// Turn DEBUG on for additional context.
|
|
39
|
-
|
|
42
|
+
if (!data) return
|
|
43
|
+
let barThickness = xMax / data.length
|
|
40
44
|
let barThicknessAdjusted = barThickness * (config.barThickness || 0.8)
|
|
41
45
|
let offset = (barThickness * (1 - (config.barThickness || 0.8))) / 2
|
|
42
46
|
|
|
43
47
|
// Tooltip helper for getting data to the closest date/category hovered.
|
|
44
48
|
const getXValueFromCoordinate = x => {
|
|
45
|
-
if (config.xAxis.type === 'categorical') {
|
|
49
|
+
if (config.xAxis.type === 'categorical' || config.visualizationType === 'Combo') {
|
|
46
50
|
let eachBand = xScale.step()
|
|
47
51
|
let numerator = x
|
|
48
52
|
const index = Math.floor(Number(numerator) / eachBand)
|
|
49
53
|
return xScale.domain()[index - 1] // fixes off by 1 error
|
|
50
54
|
}
|
|
51
55
|
|
|
52
|
-
if (config.xAxis.type === 'date') {
|
|
56
|
+
if (config.xAxis.type === 'date' && config.visualizationType !== 'Combo') {
|
|
53
57
|
const bisectDate = bisector(d => parseDate(d[config.xAxis.dataKey])).left
|
|
54
58
|
const x0 = xScale.invert(x)
|
|
55
59
|
const index = bisectDate(config.data, x0, 1)
|
|
@@ -58,51 +62,55 @@ const CoveAreaChart = ({ xScale, yScale, yMax, xMax }) => {
|
|
|
58
62
|
}
|
|
59
63
|
}
|
|
60
64
|
|
|
61
|
-
const handleMouseOver =
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
const { x, y } = eventSvgCoords
|
|
67
|
-
|
|
68
|
-
let closestXScaleValue = getXValueFromCoordinate(x)
|
|
69
|
-
let formattedDate = formatDate(closestXScaleValue)
|
|
70
|
-
|
|
71
|
-
let yScaleValues
|
|
72
|
-
if (config.xAxis.type === 'categorical') {
|
|
73
|
-
yScaleValues = data.filter(d => d[config.xAxis.dataKey] === closestXScaleValue)
|
|
74
|
-
} else {
|
|
75
|
-
yScaleValues = data.filter(d => d[config.xAxis.dataKey] === formattedDate)
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
let seriesToInclude = []
|
|
79
|
-
let yScaleMaxValues = []
|
|
80
|
-
let itemsToLoop = [config.runtime.xAxis.dataKey, ...config.runtime.seriesKeys]
|
|
65
|
+
const handleMouseOver = (e, data) => {
|
|
66
|
+
// get the svg coordinates of the mouse
|
|
67
|
+
// and get the closest values
|
|
68
|
+
const eventSvgCoords = localPoint(e)
|
|
69
|
+
const { x, y } = eventSvgCoords
|
|
81
70
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
})
|
|
71
|
+
let closestXScaleValue = getXValueFromCoordinate(x)
|
|
72
|
+
let formattedDate = formatDate(closestXScaleValue)
|
|
85
73
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
tooltipData.dataXPosition = isEditor ? 300 + x + 20 : x + 20
|
|
93
|
-
tooltipData.dataYPosition = y - 20
|
|
74
|
+
let yScaleValues
|
|
75
|
+
if (config.xAxis.type === 'categorical') {
|
|
76
|
+
yScaleValues = data.filter(d => d[config.xAxis.dataKey] === closestXScaleValue)
|
|
77
|
+
} else {
|
|
78
|
+
yScaleValues = data.filter(d => formatDate(parseDate(d[config.xAxis.dataKey])) === formattedDate)
|
|
79
|
+
}
|
|
94
80
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
81
|
+
let seriesToInclude = []
|
|
82
|
+
let yScaleMaxValues = []
|
|
83
|
+
let itemsToLoop = [config.runtime.xAxis.dataKey, ...config.runtime.seriesKeys]
|
|
84
|
+
|
|
85
|
+
itemsToLoop.map(seriesKey => {
|
|
86
|
+
if (!seriesKey) return
|
|
87
|
+
if (!yScaleValues[0]) return
|
|
88
|
+
for (const item of Object.entries(yScaleValues[0])) {
|
|
89
|
+
if (item[0] === seriesKey) {
|
|
90
|
+
seriesToInclude.push(item)
|
|
91
|
+
}
|
|
100
92
|
}
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// filter out the series that aren't added to the map.
|
|
96
|
+
seriesToInclude.map(series => yScaleMaxValues.push(Number(yScaleValues[0][series])))
|
|
97
|
+
if (!seriesToInclude) return
|
|
98
|
+
let tooltipDataFromSeries = Object.fromEntries(seriesToInclude) ? Object.fromEntries(seriesToInclude) : {}
|
|
99
|
+
|
|
100
|
+
let tooltipData = {}
|
|
101
|
+
tooltipData.data = tooltipDataFromSeries
|
|
102
|
+
tooltipData.dataXPosition = x + 20
|
|
103
|
+
tooltipData.dataYPosition = y - 100
|
|
104
|
+
|
|
105
|
+
let tooltipInformation = {
|
|
106
|
+
tooltipData: tooltipData,
|
|
107
|
+
tooltipTop: 0,
|
|
108
|
+
tooltipValues: yScaleValues,
|
|
109
|
+
tooltipLeft: x
|
|
110
|
+
}
|
|
101
111
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
[showTooltip] // eslint-disable-line
|
|
105
|
-
)
|
|
112
|
+
showTooltip(tooltipInformation)
|
|
113
|
+
}
|
|
106
114
|
|
|
107
115
|
const TooltipListItem = ({ item }) => {
|
|
108
116
|
const [label, value] = item
|
|
@@ -113,59 +121,94 @@ const CoveAreaChart = ({ xScale, yScale, yMax, xMax }) => {
|
|
|
113
121
|
return config.xAxis.type === 'date' ? xScale(parseDate(d[config.xAxis.dataKey])) : xScale(d[config.xAxis.dataKey])
|
|
114
122
|
}
|
|
115
123
|
|
|
116
|
-
const handleY = (d, index) => {
|
|
117
|
-
return yScale(d[
|
|
124
|
+
const handleY = (d, index, s = undefined) => {
|
|
125
|
+
return yScale(d[s.dataKey])
|
|
118
126
|
}
|
|
119
127
|
|
|
120
128
|
return (
|
|
121
129
|
data && (
|
|
122
130
|
<ErrorBoundary component='AreaChart'>
|
|
123
|
-
<Group className='area-chart' key='area-wrapper' left={config.yAxis.size}>
|
|
124
|
-
{config.
|
|
125
|
-
let
|
|
131
|
+
<Group className='area-chart' key='area-wrapper' left={Number(config.yAxis.size)}>
|
|
132
|
+
{(config.runtime.areaSeriesKeys || config.runtime.seriesKeys).map((s, index) => {
|
|
133
|
+
let seriesData = data.map(d => {
|
|
134
|
+
return {
|
|
135
|
+
[config.xAxis.dataKey]: d[config.xAxis.dataKey],
|
|
136
|
+
[s.dataKey]: d[s.dataKey]
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
|
|
126
140
|
let curveType = allCurves[s.lineType]
|
|
127
141
|
let transparentArea = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(s.dataKey) === -1
|
|
128
142
|
let displayArea = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(s.dataKey) !== -1
|
|
129
143
|
|
|
130
|
-
|
|
144
|
+
if (config.xAxis.type === 'date') {
|
|
145
|
+
data.map(d => xScale(parseDate(d[config.xAxis.dataKey])))
|
|
146
|
+
}
|
|
131
147
|
|
|
132
148
|
return (
|
|
133
|
-
|
|
149
|
+
<React.Fragment key={index}>
|
|
134
150
|
{/* prettier-ignore */}
|
|
135
|
-
|
|
136
|
-
|
|
151
|
+
<LinePath
|
|
152
|
+
data={seriesData}
|
|
153
|
+
x={d => handleX(d)}
|
|
154
|
+
y={d => handleY(d, index, s)}
|
|
155
|
+
stroke={displayArea ? colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[s.dataKey] : s.dataKey) : '#000' : 'transparent'}
|
|
156
|
+
strokeWidth={2}
|
|
157
|
+
strokeOpacity={1}
|
|
158
|
+
shapeRendering='geometricPrecision'
|
|
159
|
+
curve={curveType}
|
|
160
|
+
strokeDasharray={s.type ? handleLineType(s.type) : 0}
|
|
161
|
+
/>
|
|
137
162
|
|
|
138
163
|
{/* prettier-ignore */}
|
|
139
|
-
|
|
140
|
-
|
|
164
|
+
<AreaClosed
|
|
165
|
+
key={'area-chart'}
|
|
166
|
+
fill={ displayArea ? colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[s.dataKey] : s.dataKey) : '#000' : 'transparent'}
|
|
167
|
+
fillOpacity={transparentArea ? 0.25 : 0.5}
|
|
168
|
+
data={seriesData}
|
|
169
|
+
x={d => handleX(d)}
|
|
170
|
+
y={d => handleY(d, index, s)}
|
|
171
|
+
yScale={yScale}
|
|
172
|
+
curve={curveType}
|
|
173
|
+
strokeDasharray={s.type ? handleLineType(s.type) : 0}
|
|
174
|
+
/>
|
|
141
175
|
|
|
142
|
-
|
|
176
|
+
{/* Transparent bar for tooltips */}
|
|
177
|
+
{/* prettier-ignore */}
|
|
178
|
+
<Bar
|
|
179
|
+
width={ Number(xMax)}
|
|
180
|
+
height={ Number(yMax)}
|
|
181
|
+
fill={DEBUG ? 'red' : 'transparent'}
|
|
182
|
+
fillOpacity={0.05}
|
|
183
|
+
style={DEBUG ? { stroke: 'black', strokeWidth: 2 } : {}}
|
|
184
|
+
onMouseMove={e => handleMouseOver(e, data)}
|
|
185
|
+
/>
|
|
143
186
|
|
|
144
187
|
{/* circles that appear on hover */}
|
|
145
|
-
{tooltipData && (
|
|
188
|
+
{tooltipData && Object.entries(tooltipData.data).length > 0 && (
|
|
146
189
|
<circle
|
|
147
190
|
cx={config.xAxis.type === 'categorical' ? xScale(tooltipData.data[config.xAxis.dataKey]) : xScale(parseDate(tooltipData.data[config.xAxis.dataKey]))}
|
|
148
191
|
cy={yScale(tooltipData.data[s.dataKey])}
|
|
149
192
|
r={4.5}
|
|
150
193
|
opacity={1}
|
|
151
194
|
fillOpacity={1}
|
|
152
|
-
fill={
|
|
195
|
+
fill={displayArea ? (colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[s.dataKey] : s.dataKey) : '#000') : 'transparent'}
|
|
153
196
|
style={{ filter: 'unset', opacity: 1 }}
|
|
154
197
|
/>
|
|
155
198
|
)}
|
|
156
199
|
|
|
157
|
-
{/* bars
|
|
200
|
+
{/* another tool for showing bars during debug mode. */}
|
|
158
201
|
{DEBUG &&
|
|
159
|
-
|
|
202
|
+
data.map((item, index) => {
|
|
160
203
|
return (
|
|
161
204
|
<Bar
|
|
162
205
|
className='bar-here'
|
|
163
|
-
x={barThickness * index
|
|
164
|
-
y={d => yScale(d[config.series[index].dataKey])}
|
|
206
|
+
x={Number(barThickness * index)}
|
|
207
|
+
y={d => Number(yScale(d[config.series[index].dataKey]))}
|
|
165
208
|
yScale={yScale}
|
|
166
|
-
width={
|
|
209
|
+
width={Number(barThickness)}
|
|
167
210
|
height={yMax}
|
|
168
|
-
fill={'transparent'}
|
|
211
|
+
fill={DEBUG ? 'red' : 'transparent'}
|
|
169
212
|
fillOpacity={1}
|
|
170
213
|
style={{ stroke: 'black', strokeWidth: 2 }}
|
|
171
214
|
onMouseMove={e => handleMouseOver(e, data)}
|
|
@@ -173,20 +216,19 @@ const CoveAreaChart = ({ xScale, yScale, yMax, xMax }) => {
|
|
|
173
216
|
)
|
|
174
217
|
})}
|
|
175
218
|
|
|
176
|
-
{tooltipData && (
|
|
177
|
-
<TooltipInPortal key={Math.random()} top={tooltipData.dataYPosition} left={tooltipData.dataXPosition} style={defaultStyles}>
|
|
178
|
-
<
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
<li>
|
|
219
|
+
{tooltipData && Object.entries(tooltipData.data).length > 0 && (
|
|
220
|
+
<TooltipInPortal key={Math.random()} top={tooltipData.dataYPosition + chartPosition?.top} left={tooltipData.dataXPosition + chartPosition?.left} style={defaultStyles}>
|
|
221
|
+
<ul style={{ listStyle: 'none', paddingLeft: 'unset', fontFamily: 'sans-serif', margin: 'auto', lineHeight: '1rem' }} data-tooltip-id={tooltip_id}>
|
|
222
|
+
{typeof tooltipData === 'object' &&
|
|
223
|
+
Object.entries(tooltipData.data).map(item => (
|
|
224
|
+
<li style={{ padding: '2.5px 0' }}>
|
|
182
225
|
<TooltipListItem item={item} />
|
|
183
226
|
</li>
|
|
184
227
|
))}
|
|
185
|
-
|
|
186
|
-
</Group>
|
|
228
|
+
</ul>
|
|
187
229
|
</TooltipInPortal>
|
|
188
230
|
)}
|
|
189
|
-
|
|
231
|
+
</React.Fragment>
|
|
190
232
|
)
|
|
191
233
|
})}
|
|
192
234
|
</Group>
|
|
@@ -6,16 +6,14 @@ import chroma from 'chroma-js'
|
|
|
6
6
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
7
7
|
import ConfigContext from '../ConfigContext'
|
|
8
8
|
import { BarStackHorizontal } from '@visx/shape'
|
|
9
|
+
import { useHighlightedBars } from '../hooks/useHighlightedBars'
|
|
9
10
|
|
|
10
11
|
export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getXAxisData, getYAxisData, animatedChart, visible }) {
|
|
11
|
-
const { transformedData: data, colorScale, seriesHighlight, config, formatNumber, updateConfig, colorPalettes, formatDate, isNumber,
|
|
12
|
-
|
|
13
|
-
// calling clean several times on same set of data (TT)
|
|
14
|
-
const cleanedData = cleanData(data, config.xAxis.dataKey)
|
|
15
|
-
|
|
12
|
+
const { transformedData: data, colorScale, seriesHighlight, config, formatNumber, updateConfig, colorPalettes, tableData, formatDate, isNumber, getTextWidth, parseDate } = useContext(ConfigContext)
|
|
13
|
+
const { HighLightedBarUtils } = useHighlightedBars(config)
|
|
16
14
|
const { orientation, visualizationSubType } = config
|
|
17
15
|
const isHorizontal = orientation === 'horizontal'
|
|
18
|
-
|
|
16
|
+
const barBorderWidth = 1
|
|
19
17
|
const lollipopBarWidth = config.lollipopSize === 'large' ? 7 : config.lollipopSize === 'medium' ? 6 : 5
|
|
20
18
|
const lollipopShapeSize = config.lollipopSize === 'large' ? 14 : config.lollipopSize === 'medium' ? 12 : 10
|
|
21
19
|
|
|
@@ -28,21 +26,18 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
28
26
|
const tipRounding = config.tipRounding
|
|
29
27
|
const radius = config.roundingStyle === 'standard' ? '8px' : config.roundingStyle === 'shallow' ? '5px' : config.roundingStyle === 'finger' ? '15px' : '0px'
|
|
30
28
|
const stackCount = config.runtime.seriesKeys.length
|
|
31
|
-
const barBorderWidth = 1
|
|
32
29
|
const fontSize = { small: 16, medium: 18, large: 20 }
|
|
33
30
|
const hasMultipleSeries = Object.keys(config.runtime.seriesLabels).length > 1
|
|
34
31
|
|
|
35
|
-
const applyRadius =
|
|
36
|
-
if (index === undefined || index === null || !isRounded) return
|
|
32
|
+
const applyRadius = index => {
|
|
33
|
+
if (index === undefined || index === null || !isRounded) return {}
|
|
37
34
|
let style = {}
|
|
38
35
|
|
|
39
36
|
if ((isStacked && index + 1 === stackCount) || !isStacked) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
style = isHorizontal ? { borderRadius: `0 ${radius} ${radius} 0` } : { borderRadius: `${radius} ${radius} 0 0` }
|
|
45
|
-
}
|
|
37
|
+
style = isHorizontal ? { borderRadius: `0 ${radius} ${radius} 0` } : { borderRadius: `${radius} ${radius} 0 0` }
|
|
38
|
+
}
|
|
39
|
+
if (!isStacked && index === -1) {
|
|
40
|
+
style = isHorizontal ? { borderRadius: `${radius} 0 0 ${radius} ` } : { borderRadius: ` 0 0 ${radius} ${radius}` }
|
|
46
41
|
}
|
|
47
42
|
if (tipRounding === 'full' && isStacked && index === 0 && stackCount > 1) {
|
|
48
43
|
style = isHorizontal ? { borderRadius: `${radius} 0 0 ${radius}` } : { borderRadius: `0 0 ${radius} ${radius}` }
|
|
@@ -52,7 +47,27 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
52
47
|
}
|
|
53
48
|
return style
|
|
54
49
|
}
|
|
55
|
-
|
|
50
|
+
|
|
51
|
+
const assignColorsToValues = () => {
|
|
52
|
+
const palettesArr = colorPalettes[config.palette]
|
|
53
|
+
const values = tableData.map(d => {
|
|
54
|
+
return d[config.legend.colorCode]
|
|
55
|
+
})
|
|
56
|
+
// Map to hold unique values and their colors
|
|
57
|
+
let colorMap = new Map()
|
|
58
|
+
// Resultant array to hold colors to the values
|
|
59
|
+
let result = []
|
|
60
|
+
|
|
61
|
+
for (let i = 0; i < values.length; i++) {
|
|
62
|
+
// If value not in map, add it and assign a color
|
|
63
|
+
if (!colorMap.has(values[i])) {
|
|
64
|
+
colorMap.set(values[i], palettesArr[colorMap.size % palettesArr.length])
|
|
65
|
+
}
|
|
66
|
+
// push the colosr to the result array
|
|
67
|
+
result.push(colorMap.get(values[i]))
|
|
68
|
+
}
|
|
69
|
+
return result
|
|
70
|
+
}
|
|
56
71
|
|
|
57
72
|
const updateBars = defaultBars => {
|
|
58
73
|
// function updates stacked && regular && lollipop horizontal bars
|
|
@@ -136,7 +151,7 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
136
151
|
<Group left={parseFloat(config.runtime.yAxis.size)}>
|
|
137
152
|
{/* Stacked Vertical */}
|
|
138
153
|
{config.visualizationSubType === 'stacked' && !isHorizontal && (
|
|
139
|
-
<BarStack data={
|
|
154
|
+
<BarStack data={data} keys={config.runtime.barSeriesKeys || config.runtime.seriesKeys} x={d => d[config.runtime.xAxis.dataKey]} xScale={xScale} yScale={yScale} color={colorScale}>
|
|
140
155
|
{barStacks =>
|
|
141
156
|
barStacks.reverse().map(barStack =>
|
|
142
157
|
barStack.bars.map(bar => {
|
|
@@ -148,7 +163,8 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
148
163
|
// tooltips
|
|
149
164
|
const xAxisValue = config.runtime.xAxis.type === 'date' ? formatDate(parseDate(data[bar.index][config.runtime.xAxis.dataKey])) : data[bar.index][config.runtime.xAxis.dataKey]
|
|
150
165
|
const yAxisValue = formatNumber(bar.bar ? bar.bar.data[bar.key] : 0, 'left')
|
|
151
|
-
|
|
166
|
+
|
|
167
|
+
const style = applyRadius(barStack.index)
|
|
152
168
|
let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
|
|
153
169
|
const xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
|
|
154
170
|
if (!hasMultipleSeries) {
|
|
@@ -172,7 +188,7 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
172
188
|
`}
|
|
173
189
|
</style>
|
|
174
190
|
<Group key={`bar-stack-${barStack.index}-${bar.index}`} id={`barStack${barStack.index}-${bar.index}`} className='stack vertical'>
|
|
175
|
-
<Text display={config.labels && displayBar ? 'block' : 'none'} opacity={transparentBar ? 0.5 : 1} x={barThickness * bar.index + offset} y={bar.y - 5} fill={
|
|
191
|
+
<Text display={config.labels && displayBar ? 'block' : 'none'} opacity={transparentBar ? 0.5 : 1} x={barThickness * bar.index + offset} y={bar.y - 5} fill={'#000'} textAnchor='middle'>
|
|
176
192
|
{yAxisValue}
|
|
177
193
|
</Text>
|
|
178
194
|
<foreignObject
|
|
@@ -199,7 +215,7 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
199
215
|
{/* Stacked Horizontal */}
|
|
200
216
|
{config.visualizationSubType === 'stacked' && isHorizontal && (
|
|
201
217
|
<>
|
|
202
|
-
<BarStackHorizontal data={
|
|
218
|
+
<BarStackHorizontal data={data} keys={config.runtime.barSeriesKeys || config.runtime.seriesKeys} height={yMax} y={d => d[config.runtime.yAxis.dataKey]} xScale={xScale} yScale={yScale} color={colorScale} offset='none'>
|
|
203
219
|
{barStacks =>
|
|
204
220
|
barStacks.map(barStack =>
|
|
205
221
|
updateBars(barStack.bars).map((bar, index) => {
|
|
@@ -210,7 +226,7 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
210
226
|
// tooltips
|
|
211
227
|
const xAxisValue = formatNumber(data[bar.index][bar.key], 'left')
|
|
212
228
|
const yAxisValue = config.runtime.yAxis.type === 'date' ? formatDate(parseDate(data[bar.index][config.runtime.originalXAxis.dataKey])) : data[bar.index][config.runtime.originalXAxis.dataKey]
|
|
213
|
-
const style = applyRadius(barStack.index
|
|
229
|
+
const style = applyRadius(barStack.index)
|
|
214
230
|
let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
|
|
215
231
|
let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
|
|
216
232
|
if (!hasMultipleSeries) {
|
|
@@ -297,7 +313,7 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
297
313
|
{config.visualizationSubType !== 'stacked' && (
|
|
298
314
|
<Group>
|
|
299
315
|
<BarGroup
|
|
300
|
-
data={
|
|
316
|
+
data={data}
|
|
301
317
|
keys={config.runtime.barSeriesKeys || config.runtime.seriesKeys}
|
|
302
318
|
height={yMax}
|
|
303
319
|
x0={d => d[config.runtime.originalXAxis.dataKey]}
|
|
@@ -318,22 +334,44 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
318
334
|
left={config.runtime.horizontal ? 0 : (xMax / barGroups.length) * barGroup.index}
|
|
319
335
|
>
|
|
320
336
|
{barGroup.bars.map((bar, index) => {
|
|
337
|
+
const scaleVal = config.useLogScale ? 0.1 : 0
|
|
338
|
+
const getHighlightedBarColorByValue = value => {
|
|
339
|
+
const match = config?.highlightedBarValues.filter(item => {
|
|
340
|
+
if (!item.value) return
|
|
341
|
+
return config.xAxis.type === 'date' ? formatDate(parseDate(item.value)) === value : item.value === value
|
|
342
|
+
})[0]
|
|
343
|
+
|
|
344
|
+
if (!match?.color) return `rgba(255, 102, 1)`
|
|
345
|
+
return match.color
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
const getHighlightedBarByValue = value => {
|
|
349
|
+
const match = config?.highlightedBarValues.filter(item => {
|
|
350
|
+
if (!item.value) return
|
|
351
|
+
return config.xAxis.type === 'date' ? formatDate(parseDate(item.value)) === value : item.value === value
|
|
352
|
+
})[0]
|
|
353
|
+
|
|
354
|
+
if (!match?.color) return false
|
|
355
|
+
return match
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
let highlightedBarValues = config.highlightedBarValues.map(item => item.value).filter(item => item !== ('' || undefined))
|
|
359
|
+
|
|
360
|
+
highlightedBarValues = config.xAxis.type === 'date' ? HighLightedBarUtils.formatDates(highlightedBarValues) : highlightedBarValues
|
|
361
|
+
|
|
321
362
|
let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
|
|
322
363
|
let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
|
|
323
|
-
let barHeight = orientation === 'horizontal' ? config.barHeight : isNumber(Math.abs(yScale(bar.value) - yScale(
|
|
364
|
+
let barHeight = orientation === 'horizontal' ? config.barHeight : isNumber(Math.abs(yScale(bar.value) - yScale(scaleVal))) ? Math.abs(yScale(bar.value) - yScale(scaleVal)) : 0
|
|
324
365
|
let barY = bar.value >= 0 && isNumber(bar.value) ? bar.y : yScale(0)
|
|
325
366
|
let barGroupWidth = ((config.runtime.horizontal ? yMax : xMax) / barGroups.length) * (config.barThickness || 0.8)
|
|
326
367
|
let offset = (((config.runtime.horizontal ? yMax : xMax) / barGroups.length) * (1 - (config.barThickness || 0.8))) / 2
|
|
327
|
-
|
|
368
|
+
const barX = bar.value < 0 ? Math.abs(xScale(bar.value)) : xScale(0)
|
|
369
|
+
const barWidthHorizontal = Math.abs(xScale(bar.value) - xScale(scaleVal))
|
|
328
370
|
// ! Unsure if this should go back.
|
|
329
371
|
if (config.isLollipopChart) {
|
|
330
372
|
offset = (config.runtime.horizontal ? yMax : xMax) / barGroups.length / 2 - lollipopBarWidth / 2
|
|
331
373
|
}
|
|
332
|
-
|
|
333
|
-
data.forEach(d => set.add(d[config.legend.colorCode]))
|
|
334
|
-
const uniqValues = Array.from(set)
|
|
335
|
-
|
|
336
|
-
let palette = colorPalettes[config.palette].slice(0, uniqValues.length)
|
|
374
|
+
let palette = assignColorsToValues()
|
|
337
375
|
|
|
338
376
|
let barWidth = config.isLollipopChart ? lollipopBarWidth : barGroupWidth / barGroup.bars.length
|
|
339
377
|
let barColor = config.runtime.seriesLabels && config.runtime.seriesLabels[bar.key] ? colorScale(config.runtime.seriesLabels[bar.key]) : colorScale(bar.key)
|
|
@@ -351,18 +389,42 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
351
389
|
xAxisValue = tempValue
|
|
352
390
|
barWidth = config.barHeight
|
|
353
391
|
}
|
|
392
|
+
|
|
393
|
+
const barPosition = bar.value < 0 ? 'below' : 'above'
|
|
394
|
+
|
|
354
395
|
// check if bar text/value string fits into each bars.
|
|
355
396
|
let textWidth = getTextWidth(xAxisValue, `normal ${fontSize[config.fontSize]}px sans-serif`)
|
|
356
|
-
let textFits = textWidth <
|
|
357
|
-
|
|
397
|
+
let textFits = textWidth < barWidthHorizontal - 5 // minus padding 5
|
|
358
398
|
let labelColor = '#000000'
|
|
359
399
|
|
|
360
400
|
// Set label color
|
|
361
|
-
if (
|
|
362
|
-
if (
|
|
401
|
+
if (barColor && labelColor) {
|
|
402
|
+
if (chroma.contrast(labelColor, barColor) < 4.9) {
|
|
403
|
+
labelColor = textFits ? '#FFFFFF' : '#000000'
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Set if background is transparent'
|
|
408
|
+
labelColor = HighLightedBarUtils.checkFontColor(yAxisValue, highlightedBarValues, labelColor)
|
|
409
|
+
|
|
410
|
+
// control text position
|
|
411
|
+
let textAnchor = textFits ? 'end' : 'start'
|
|
412
|
+
let textAnchorLollipop = 'start'
|
|
413
|
+
let textPadding = textFits ? -5 : 5
|
|
414
|
+
let textPaddingLollipop = 10
|
|
415
|
+
// if bars are negative we change positions of text
|
|
416
|
+
if (barPosition === 'below') {
|
|
417
|
+
textAnchor = textFits ? 'start' : 'end'
|
|
418
|
+
textPadding = textFits ? 5 : -5
|
|
419
|
+
if (config.isLollipopChart) {
|
|
420
|
+
textAnchorLollipop = 'end'
|
|
421
|
+
textPaddingLollipop = -10
|
|
422
|
+
}
|
|
363
423
|
}
|
|
364
424
|
|
|
365
|
-
|
|
425
|
+
// create new Index based on bar value for border Radius
|
|
426
|
+
const newIndex = bar.value < 0 ? -1 : index
|
|
427
|
+
const style = applyRadius(newIndex)
|
|
366
428
|
|
|
367
429
|
let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
|
|
368
430
|
let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
|
|
@@ -379,6 +441,26 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
379
441
|
${xAxisTooltip}
|
|
380
442
|
</div>`
|
|
381
443
|
|
|
444
|
+
const isRegularLollipopColor = config.isLollipopChart && config.lollipopColorStyle === 'regular'
|
|
445
|
+
const isTwoToneLollipopColor = config.isLollipopChart && config.lollipopColorStyle === 'two-tone'
|
|
446
|
+
const isHighlightedBar = config.orientation === 'vertical' ? highlightedBarValues?.includes(xAxisValue) : highlightedBarValues?.includes(yAxisValue)
|
|
447
|
+
const highlightedBarColor = config.orientation === 'vertical' ? getHighlightedBarColorByValue(xAxisValue) : getHighlightedBarColorByValue(yAxisValue)
|
|
448
|
+
const highlightedBar = config.orientation === 'vertical' ? getHighlightedBarByValue(xAxisValue) : getHighlightedBarByValue(yAxisValue)
|
|
449
|
+
|
|
450
|
+
const background = isRegularLollipopColor ? barColor : isTwoToneLollipopColor ? chroma(barColor).brighten(1) : isHighlightedBar ? 'transparent' : barColor
|
|
451
|
+
|
|
452
|
+
const borderColor = isHighlightedBar ? highlightedBarColor : config.barHasBorder === 'true' ? '#000' : 'transparent'
|
|
453
|
+
|
|
454
|
+
const borderWidth = isHighlightedBar ? highlightedBar.borderWidth : config.isLollipopChart ? 0 : config.barHasBorder === 'true' ? barBorderWidth : 0
|
|
455
|
+
|
|
456
|
+
const finalStyle = {
|
|
457
|
+
background,
|
|
458
|
+
borderColor,
|
|
459
|
+
borderStyle: 'solid',
|
|
460
|
+
borderWidth,
|
|
461
|
+
...style
|
|
462
|
+
}
|
|
463
|
+
|
|
382
464
|
return (
|
|
383
465
|
<Group key={`${barGroup.index}--${index}--${orientation}`}>
|
|
384
466
|
{/* This feels gross but inline transition was not working well*/}
|
|
@@ -394,15 +476,11 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
394
476
|
<foreignObject
|
|
395
477
|
id={`barGroup${barGroup.index}`}
|
|
396
478
|
key={`bar-group-bar-${barGroup.index}-${bar.index}-${bar.value}-${bar.key}`}
|
|
397
|
-
x={config.runtime.horizontal ?
|
|
479
|
+
x={config.runtime.horizontal ? barX : barWidth * bar.index + offset}
|
|
398
480
|
y={config.runtime.horizontal ? barWidth * bar.index : barY}
|
|
399
|
-
width={config.runtime.horizontal ?
|
|
481
|
+
width={config.runtime.horizontal ? barWidthHorizontal : barWidth}
|
|
400
482
|
height={isHorizontal && !config.isLollipopChart ? barWidth : isHorizontal && config.isLollipopChart ? lollipopBarWidth : barHeight}
|
|
401
|
-
style={
|
|
402
|
-
background: config.isLollipopChart && config.lollipopColorStyle === 'regular' ? barColor : config.isLollipopChart && config.lollipopColorStyle === 'two-tone' ? chroma(barColor).brighten(1) : barColor,
|
|
403
|
-
border: `${config.isLollipopChart ? 0 : config.barHasBorder === 'true' ? barBorderWidth : 0}px solid #333`,
|
|
404
|
-
...style
|
|
405
|
-
}}
|
|
483
|
+
style={finalStyle}
|
|
406
484
|
opacity={transparentBar ? 0.5 : 1}
|
|
407
485
|
display={displayBar ? 'block' : 'none'}
|
|
408
486
|
data-tooltip-html={tooltip}
|
|
@@ -414,21 +492,21 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
414
492
|
x={bar.y}
|
|
415
493
|
y={config.barHeight / 2 + config.barHeight * bar.index}
|
|
416
494
|
fill={labelColor}
|
|
417
|
-
dx={
|
|
495
|
+
dx={textPadding}
|
|
418
496
|
verticalAnchor='middle'
|
|
419
|
-
textAnchor={
|
|
497
|
+
textAnchor={textAnchor}
|
|
420
498
|
>
|
|
421
499
|
{xAxisValue}
|
|
422
500
|
</Text>
|
|
423
501
|
)}
|
|
424
|
-
;
|
|
425
502
|
{orientation === 'horizontal' && config.isLollipopChart && displayNumbersOnBar && (
|
|
426
503
|
<Text
|
|
427
504
|
display={displayBar ? 'block' : 'none'}
|
|
428
|
-
x={
|
|
505
|
+
x={bar.y} // padding
|
|
429
506
|
y={0}
|
|
430
507
|
fill={'#000000'}
|
|
431
|
-
|
|
508
|
+
dx={textPaddingLollipop}
|
|
509
|
+
textAnchor={textAnchorLollipop}
|
|
432
510
|
verticalAnchor='middle'
|
|
433
511
|
fontWeight={'normal'}
|
|
434
512
|
>
|
|
@@ -444,13 +522,12 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
|
|
|
444
522
|
: formatNumber(data[barGroup.index][config.runtime.originalXAxis.dataKey])}
|
|
445
523
|
</Text>
|
|
446
524
|
)}
|
|
447
|
-
|
|
525
|
+
|
|
448
526
|
{orientation === 'vertical' && (
|
|
449
|
-
<Text display={config.labels && displayBar ? 'block' : 'none'} opacity={transparentBar ? 0.5 : 1} x={barWidth * (bar.index + 0.5) + offset} y={barY - 5} fill={
|
|
527
|
+
<Text display={config.labels && displayBar ? 'block' : 'none'} opacity={transparentBar ? 0.5 : 1} x={barWidth * (bar.index + 0.5) + offset} y={barY - 5} fill={labelColor} textAnchor='middle'>
|
|
450
528
|
{yAxisValue}
|
|
451
529
|
</Text>
|
|
452
530
|
)}
|
|
453
|
-
;
|
|
454
531
|
{config.isLollipopChart && config.lollipopShape === 'circle' && (
|
|
455
532
|
<circle
|
|
456
533
|
cx={orientation === 'horizontal' ? bar.y : barWidth * (barGroup.bars.length - bar.index - 1) + (isLabelBelowBar && orientation === 'horizontal' ? 0 : offset) + lollipopShapeSize / 3.5}
|