@cdc/chart 4.24.1 → 4.24.3
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 +48948 -37923
- package/examples/{private/combo.json → chart-regression-1.json} +40 -31
- package/examples/chart-regression-2.json +2360 -0
- package/examples/feature/filters/url-filter.json +1076 -0
- package/examples/feature/line/line-chart-preliminary.json +84 -37
- package/examples/feature/line/line-chart.json +2 -1
- package/examples/feature/regions/index.json +55 -5
- package/examples/feature/sankey/sankey-example-data.json +1364 -0
- package/examples/feature/sankey/sankey_chart_data.csv +20 -0
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +306 -19
- package/examples/sparkline.json +868 -0
- package/index.html +128 -121
- package/package.json +4 -2
- package/src/CdcChart.tsx +73 -38
- package/src/_stories/ChartEditor.stories.tsx +15 -4
- package/src/_stories/_mock/pie_config.json +4 -3
- package/src/_stories/_mock/url_filter.json +1076 -0
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +2 -1
- package/src/components/AreaChart/components/AreaChart.jsx +2 -25
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +39 -49
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +36 -56
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +36 -41
- package/src/components/BarChart/components/BarChart.Vertical.tsx +48 -64
- package/src/components/BoxPlot/BoxPlot.jsx +11 -9
- package/src/components/DeviationBar.jsx +3 -3
- package/src/components/EditorPanel/EditorPanel.tsx +1717 -1961
- package/src/components/EditorPanel/EditorPanelContext.ts +40 -0
- package/src/components/EditorPanel/components/Panels/Panel.BoxPlot.tsx +148 -0
- package/src/components/EditorPanel/components/{Panel.ForestPlotSettings.tsx → Panels/Panel.ForestPlotSettings.tsx} +16 -7
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +160 -0
- package/src/components/EditorPanel/components/{Panel.Regions.tsx → Panels/Panel.Regions.tsx} +6 -6
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +108 -0
- package/src/components/EditorPanel/components/{Panel.Series.tsx → Panels/Panel.Series.tsx} +50 -6
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +338 -0
- package/src/components/EditorPanel/components/Panels/index.tsx +19 -0
- package/src/components/EditorPanel/components/panels.scss +11 -0
- package/src/components/EditorPanel/editor-panel.scss +1 -13
- package/src/components/EditorPanel/useEditorPermissions.js +44 -13
- package/src/components/Legend/Legend.Component.tsx +207 -0
- package/src/components/Legend/Legend.tsx +8 -327
- package/src/components/Legend/helpers/createFormatLabels.tsx +140 -0
- package/src/components/LineChart/LineChartProps.ts +2 -1
- package/src/components/LineChart/components/LineChart.Circle.tsx +85 -52
- package/src/components/LineChart/helpers.ts +3 -3
- package/src/components/LineChart/index.tsx +99 -23
- package/src/components/LinearChart.jsx +12 -33
- package/src/components/PairedBarChart.jsx +10 -12
- package/src/components/PieChart/PieChart.tsx +80 -27
- package/src/components/Regions/components/Regions.tsx +120 -69
- package/src/components/Sankey/index.tsx +434 -0
- package/src/components/Sankey/sankey.scss +153 -0
- package/src/components/Sankey/types/index.ts +16 -0
- package/src/components/ScatterPlot/ScatterPlot.jsx +1 -0
- package/src/components/Sparkline/{SparkLine.jsx → components/SparkLine.tsx} +14 -30
- package/src/components/Sparkline/index.scss +3 -0
- package/src/components/Sparkline/index.tsx +1 -1
- package/src/components/ZoomBrush.tsx +2 -1
- package/src/data/initial-state.js +51 -4
- package/src/helpers/computeMarginBottom.ts +4 -3
- package/src/helpers/tests/computeMarginBottom.test.ts +2 -1
- package/src/hooks/useBarChart.js +5 -2
- package/src/hooks/useHighlightedBars.js +1 -1
- package/src/hooks/useMinMax.ts +3 -3
- package/src/hooks/useScales.ts +28 -18
- package/src/hooks/useTooltip.tsx +19 -14
- package/src/scss/main.scss +8 -96
- package/src/types/ChartConfig.ts +47 -20
- package/src/types/ChartContext.ts +17 -4
- package/src/types/Label.ts +7 -0
- package/examples/private/chart-t.json +0 -3740
- package/examples/private/epi-data.csv +0 -13
- package/examples/private/epi-data.json +0 -62
- package/examples/private/epi.json +0 -403
- package/examples/private/occupancy.json +0 -109283
- package/examples/private/prod-line-config.json +0 -401
- package/examples/private/region-data.json +0 -822
- package/examples/private/region-testing.json +0 -312
- package/examples/private/scaling.json +0 -45325
- package/examples/private/testing-data.json +0 -1739
- package/examples/private/testing.json +0 -816
- package/src/components/EditorPanel/components/Panel.DateHighlighting.tsx +0 -109
- package/src/components/EditorPanel/components/Panels.tsx +0 -13
|
@@ -3,6 +3,7 @@ import React, { useContext, memo } from 'react'
|
|
|
3
3
|
// cdc
|
|
4
4
|
import ConfigContext from '../../../ConfigContext'
|
|
5
5
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
6
|
+
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
6
7
|
|
|
7
8
|
// visx & d3
|
|
8
9
|
import * as allCurves from '@visx/curve'
|
|
@@ -20,7 +21,7 @@ const AreaChartStacked = ({ xScale, yScale, yMax, xMax, handleTooltipMouseOver,
|
|
|
20
21
|
|
|
21
22
|
const handleDateCategory = value => {
|
|
22
23
|
if (config.xAxis.type === 'categorical') return xScale(value)
|
|
23
|
-
if (config.xAxis
|
|
24
|
+
if (isDateScale(config.xAxis)) {
|
|
24
25
|
let date = new Date(value)
|
|
25
26
|
return xScale(date)
|
|
26
27
|
}
|
|
@@ -3,6 +3,7 @@ import React, { useContext, memo } from 'react'
|
|
|
3
3
|
// cdc
|
|
4
4
|
import ConfigContext from '../../../ConfigContext'
|
|
5
5
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
6
|
+
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
6
7
|
|
|
7
8
|
// visx & d3
|
|
8
9
|
import * as allCurves from '@visx/curve'
|
|
@@ -18,26 +19,8 @@ const AreaChart = props => {
|
|
|
18
19
|
|
|
19
20
|
if (!data) return
|
|
20
21
|
|
|
21
|
-
// Tooltip helper for getting data to the closest date/category hovered.
|
|
22
|
-
const getXValueFromCoordinate = x => {
|
|
23
|
-
if (config.xAxis.type === 'categorical' || config.visualizationType === 'Combo') {
|
|
24
|
-
let eachBand = xScale.step()
|
|
25
|
-
let numerator = x
|
|
26
|
-
const index = Math.floor(Number(numerator) / eachBand)
|
|
27
|
-
return xScale.domain()[index - 1] // fixes off by 1 error
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
if (config.xAxis.type === 'date' && config.visualizationType !== 'Combo') {
|
|
31
|
-
const bisectDate = bisector(d => parseDate(d[config.xAxis.dataKey])).left
|
|
32
|
-
const x0 = xScale.invert(x)
|
|
33
|
-
const index = bisectDate(config.data, x0, 1)
|
|
34
|
-
const val = parseDate(config.data[index - 1][config.xAxis.dataKey])
|
|
35
|
-
return val
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
22
|
const handleX = d => {
|
|
40
|
-
return config.xAxis
|
|
23
|
+
return (isDateScale(config.xAxis) ? xScale(parseDate(d[config.xAxis.dataKey], false)) : xScale(d[config.xAxis.dataKey])) + (xScale.bandwidth ? xScale.bandwidth() / 2 : 0)
|
|
41
24
|
}
|
|
42
25
|
|
|
43
26
|
const handleY = (d, index, s = undefined) => {
|
|
@@ -61,12 +44,6 @@ const AreaChart = props => {
|
|
|
61
44
|
let transparentArea = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(s.dataKey) === -1
|
|
62
45
|
let displayArea = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(s.dataKey) !== -1
|
|
63
46
|
|
|
64
|
-
if (config.xAxis.type === 'date') {
|
|
65
|
-
data.map(d => xScale(parseDate(d[config.xAxis.dataKey])))
|
|
66
|
-
} else {
|
|
67
|
-
data.map(d => xScale(d[config.xAxis.dataKey]))
|
|
68
|
-
}
|
|
69
|
-
|
|
70
47
|
return (
|
|
71
48
|
<React.Fragment key={index}>
|
|
72
49
|
{/* prettier-ignore */}
|
|
@@ -6,19 +6,21 @@ import { Text } from '@visx/text'
|
|
|
6
6
|
import { BarGroup } from '@visx/shape'
|
|
7
7
|
import { useHighlightedBars } from '../../../hooks/useHighlightedBars'
|
|
8
8
|
import { FaStar } from 'react-icons/fa'
|
|
9
|
+
import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
|
|
9
10
|
|
|
10
11
|
// third party
|
|
11
12
|
import chroma from 'chroma-js'
|
|
12
13
|
import BarChartContext, { BarChartContextValues } from './context'
|
|
13
14
|
import { ChartContext } from '../../../types/ChartContext'
|
|
14
15
|
|
|
16
|
+
import createBarElement from '@cdc/core/components/createBarElement'
|
|
17
|
+
|
|
15
18
|
export const BarChartHorizontal = () => {
|
|
16
19
|
const { xScale, yScale, yMax, seriesScale } = useContext<BarChartContextValues>(BarChartContext)
|
|
17
20
|
const { transformedData: data, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, setSharedFilter, isNumber, getTextWidth, getYAxisData, getXAxisData } = useContext<ChartContext>(ConfigContext)
|
|
18
21
|
const {
|
|
19
22
|
isHorizontal,
|
|
20
23
|
barBorderWidth,
|
|
21
|
-
applyRadius,
|
|
22
24
|
updateBars,
|
|
23
25
|
assignColorsToValues,
|
|
24
26
|
section,
|
|
@@ -112,7 +114,6 @@ export const BarChartHorizontal = () => {
|
|
|
112
114
|
|
|
113
115
|
// create new Index for bars with negative values
|
|
114
116
|
const newIndex = bar.value < 0 ? -1 : index
|
|
115
|
-
const borderRadius = applyRadius(newIndex)
|
|
116
117
|
|
|
117
118
|
let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${xAxisValue}` : xAxisValue
|
|
118
119
|
const additionalColTooltip = getAdditionalColumn(hoveredBar)
|
|
@@ -137,10 +138,8 @@ export const BarChartHorizontal = () => {
|
|
|
137
138
|
const borderWidth = isHighlightedBar ? highlightedBar.borderWidth : config.isLollipopChart ? 0 : config.barHasBorder === 'true' ? barBorderWidth : 0
|
|
138
139
|
const displaylollipopShape = config.suppressedData.some(d => bar.key === d.column && bar.value === d.value) ? 'none' : 'block'
|
|
139
140
|
// update label color
|
|
140
|
-
if (barColor && labelColor) {
|
|
141
|
-
|
|
142
|
-
labelColor = textFits ? '#FFFFFF' : '#000000'
|
|
143
|
-
}
|
|
141
|
+
if (barColor && labelColor && textFits) {
|
|
142
|
+
labelColor = getContrastColor('#000', barColor)
|
|
144
143
|
}
|
|
145
144
|
const getTop = () => {
|
|
146
145
|
if (Number(barHeight) < 20) return -4
|
|
@@ -154,15 +153,6 @@ export const BarChartHorizontal = () => {
|
|
|
154
153
|
return 12
|
|
155
154
|
}
|
|
156
155
|
}
|
|
157
|
-
const iconStyle: { [key: string]: any } = {
|
|
158
|
-
position: 'absolute',
|
|
159
|
-
top: getTop(),
|
|
160
|
-
left: suppresedBarWidth * 1.2
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
if (config.isLollipopChart) {
|
|
164
|
-
iconStyle.top = -9
|
|
165
|
-
}
|
|
166
156
|
const background = () => {
|
|
167
157
|
if (isRegularLollipopColor) return barColor
|
|
168
158
|
if (isTwoToneLollipopColor) return chroma(barColor).brighten(1)
|
|
@@ -170,39 +160,42 @@ export const BarChartHorizontal = () => {
|
|
|
170
160
|
return barColor
|
|
171
161
|
}
|
|
172
162
|
|
|
173
|
-
const finalStyle = {
|
|
174
|
-
background: background(),
|
|
175
|
-
borderColor,
|
|
176
|
-
borderStyle: 'solid',
|
|
177
|
-
borderWidth,
|
|
178
|
-
width: barWidth,
|
|
179
|
-
transition: 'all 0.2s linear',
|
|
180
|
-
height: !config.isLollipopChart ? barHeight : lollipopBarWidth,
|
|
181
|
-
...borderRadius
|
|
182
|
-
}
|
|
183
|
-
|
|
184
163
|
return (
|
|
185
164
|
<Group key={`${barGroup.index}--${index}`}>
|
|
186
|
-
{/* This feels gross but inline transition was not working well*/}
|
|
187
|
-
<style>
|
|
188
|
-
{`
|
|
189
|
-
.linear #barGroup${barGroup.index} div,
|
|
190
|
-
.Combo #barGroup${barGroup.index} div {
|
|
191
|
-
transform-origin: 0 ${barY + barHeight}px;
|
|
192
|
-
}
|
|
193
|
-
`}
|
|
194
|
-
</style>
|
|
195
165
|
<Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
|
|
196
|
-
|
|
166
|
+
{createBarElement({
|
|
167
|
+
config: config,
|
|
168
|
+
index: newIndex,
|
|
169
|
+
id: `barGroup${barGroup.index}`,
|
|
170
|
+
background: background(),
|
|
171
|
+
borderColor,
|
|
172
|
+
borderStyle: 'solid',
|
|
173
|
+
borderWidth: `${borderWidth}px`,
|
|
174
|
+
width: barWidth,
|
|
175
|
+
height: !config.isLollipopChart ? barHeight : lollipopBarWidth,
|
|
176
|
+
x: barX,
|
|
177
|
+
y: barHeight * bar.index,
|
|
178
|
+
onMouseOver: () => onMouseOverBar(xAxisValue, bar.key),
|
|
179
|
+
onMouseLeave: onMouseLeaveBar,
|
|
180
|
+
tooltipHtml: tooltip,
|
|
181
|
+
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
182
|
+
onClick: e => {
|
|
183
|
+
e.preventDefault()
|
|
184
|
+
if (setSharedFilter) {
|
|
185
|
+
bar[config.xAxis.dataKey] = yAxisValue
|
|
186
|
+
setSharedFilter(config.uid, bar)
|
|
187
|
+
}
|
|
188
|
+
},
|
|
189
|
+
styleOverrides: {
|
|
190
|
+
transformOrigin: `0 ${barY + barHeight}px`,
|
|
191
|
+
opacity: transparentBar ? 0.2 : 1,
|
|
192
|
+
display: displayBar ? 'block' : 'none'
|
|
193
|
+
}
|
|
194
|
+
})}
|
|
195
|
+
<g
|
|
196
|
+
transform={`translate(${barX},${barHeight * bar.index})`}
|
|
197
197
|
onMouseOver={() => onMouseOverBar(xAxisValue, bar.key)}
|
|
198
198
|
onMouseLeave={onMouseLeaveBar}
|
|
199
|
-
id={`barGroup${barGroup.index}`}
|
|
200
|
-
key={`bar-group-bar-${barGroup.index}-${bar.index}-${bar.value}-${bar.key}`}
|
|
201
|
-
x={barX}
|
|
202
|
-
style={{ overflow: 'visible', ...finalStyle }}
|
|
203
|
-
y={barHeight * bar.index}
|
|
204
|
-
height={!config.isLollipopChart ? barHeight : lollipopBarWidth}
|
|
205
|
-
width={barWidth}
|
|
206
199
|
opacity={transparentBar ? 0.2 : 1}
|
|
207
200
|
display={displayBar ? 'block' : 'none'}
|
|
208
201
|
data-tooltip-html={tooltip}
|
|
@@ -215,11 +208,8 @@ export const BarChartHorizontal = () => {
|
|
|
215
208
|
}
|
|
216
209
|
}}
|
|
217
210
|
>
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
<div style={{ ...finalStyle }}></div>
|
|
221
|
-
</div>
|
|
222
|
-
</foreignObject>
|
|
211
|
+
{getIcon(bar, barWidth)}
|
|
212
|
+
</g>
|
|
223
213
|
|
|
224
214
|
{!config.isLollipopChart && displayNumbersOnBar && (
|
|
225
215
|
<Text // prettier-ignore
|
|
@@ -262,7 +252,7 @@ export const BarChartHorizontal = () => {
|
|
|
262
252
|
<circle
|
|
263
253
|
display={displaylollipopShape}
|
|
264
254
|
cx={bar.y}
|
|
265
|
-
cy={
|
|
255
|
+
cy={barHeight * bar.index + lollipopBarWidth / 2}
|
|
266
256
|
r={lollipopShapeSize / 2}
|
|
267
257
|
fill={barColor}
|
|
268
258
|
key={`circle--${bar.index}`}
|
|
@@ -4,14 +4,14 @@ import { useBarChart } from '../../../hooks/useBarChart'
|
|
|
4
4
|
import { BarStackHorizontal } from '@visx/shape'
|
|
5
5
|
import { Group } from '@visx/group'
|
|
6
6
|
import { Text } from '@visx/text'
|
|
7
|
-
|
|
8
|
-
// third party
|
|
9
|
-
import chroma from 'chroma-js'
|
|
7
|
+
import { getContrastColor } from '@cdc/core/helpers/cove/accessibility'
|
|
10
8
|
|
|
11
9
|
// types
|
|
12
10
|
import BarChartContext, { type BarChartContextValues } from './context'
|
|
13
11
|
import { type ChartContext } from '../../../types/ChartContext'
|
|
14
12
|
|
|
13
|
+
import createBarElement from '@cdc/core/components/createBarElement'
|
|
14
|
+
|
|
15
15
|
const BarChartStackedHorizontal = () => {
|
|
16
16
|
const { yMax, yScale, xScale } = useContext<BarChartContextValues>(BarChartContext)
|
|
17
17
|
|
|
@@ -30,40 +30,26 @@ const BarChartStackedHorizontal = () => {
|
|
|
30
30
|
} = useContext<ChartContext>(ConfigContext)
|
|
31
31
|
|
|
32
32
|
// prettier-ignore
|
|
33
|
-
const {
|
|
34
|
-
applyRadius,
|
|
35
|
-
barBorderWidth,
|
|
36
|
-
displayNumbersOnBar,
|
|
37
|
-
fontSize,
|
|
38
|
-
getAdditionalColumn,
|
|
39
|
-
hoveredBar,
|
|
40
|
-
isHorizontal,
|
|
41
|
-
isLabelBelowBar,
|
|
42
|
-
onMouseLeaveBar,
|
|
43
|
-
onMouseOverBar,
|
|
44
|
-
updateBars
|
|
45
|
-
} = useBarChart()
|
|
33
|
+
const { barBorderWidth, displayNumbersOnBar, fontSize, getAdditionalColumn, hoveredBar, isHorizontal, isLabelBelowBar, onMouseLeaveBar, onMouseOverBar, updateBars, barStackedSeriesKeys } = useBarChart()
|
|
46
34
|
|
|
47
35
|
const { orientation, visualizationSubType } = config
|
|
48
|
-
|
|
49
36
|
return (
|
|
50
37
|
config.visualizationSubType === 'stacked' &&
|
|
51
38
|
isHorizontal && (
|
|
52
39
|
<>
|
|
53
|
-
<BarStackHorizontal data={data} keys={
|
|
40
|
+
<BarStackHorizontal data={data} keys={barStackedSeriesKeys} height={yMax} y={d => d[config.runtime.yAxis.dataKey]} xScale={xScale} yScale={yScale} color={colorScale} offset='none'>
|
|
54
41
|
{barStacks =>
|
|
55
42
|
barStacks.map(barStack =>
|
|
56
43
|
updateBars(barStack.bars).map((bar, index) => {
|
|
57
|
-
|
|
58
|
-
|
|
44
|
+
const transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
|
|
45
|
+
const displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
|
|
59
46
|
config.barHeight = Number(config.barHeight)
|
|
60
|
-
|
|
47
|
+
const labelColor = getContrastColor('#000', colorScale(config.runtime.seriesLabels[bar.key]))
|
|
61
48
|
// tooltips
|
|
62
49
|
const xAxisValue = formatNumber(data[bar.index][bar.key], 'left')
|
|
63
50
|
const yAxisValue = config.runtime.yAxis.type === 'date' ? formatDate(parseDate(data[bar.index][config.runtime.originalXAxis.dataKey])) : data[bar.index][config.runtime.originalXAxis.dataKey]
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
let textWidth = getTextWidth(xAxisValue, `normal ${fontSize[config.fontSize]}px sans-serif`)
|
|
51
|
+
const yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
|
|
52
|
+
const textWidth = getTextWidth(xAxisValue, `normal ${fontSize[config.fontSize]}px sans-serif`)
|
|
67
53
|
|
|
68
54
|
const additionalColTooltip = getAdditionalColumn(hoveredBar)
|
|
69
55
|
const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${xAxisValue}`
|
|
@@ -73,46 +59,40 @@ const BarChartStackedHorizontal = () => {
|
|
|
73
59
|
<li class="tooltip-body ">${additionalColTooltip}</li>
|
|
74
60
|
</li></ul>`
|
|
75
61
|
|
|
76
|
-
if (chroma.contrast(labelColor, colorScale(config.runtime.seriesLabels[bar.key])) < 4.9) {
|
|
77
|
-
labelColor = '#FFFFFF'
|
|
78
|
-
}
|
|
79
|
-
|
|
80
62
|
return (
|
|
81
63
|
<>
|
|
82
|
-
<style>
|
|
83
|
-
{`
|
|
84
|
-
#barStack${barStack.index}-${bar.index} rect,
|
|
85
|
-
#barStack${barStack.index}-${bar.index} foreignObject div{
|
|
86
|
-
animation-delay: ${barStack.index * 0.5}s;
|
|
87
|
-
transform-origin: ${bar.x}px
|
|
88
|
-
}
|
|
89
|
-
`}
|
|
90
|
-
</style>
|
|
91
64
|
<Group key={index} id={`barStack${barStack.index}-${bar.index}`} className='stack horizontal'>
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
className
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
65
|
+
{createBarElement({
|
|
66
|
+
config: config,
|
|
67
|
+
seriesHighlight,
|
|
68
|
+
index: barStack.index,
|
|
69
|
+
className: `animated-chart group ${animatedChart ? 'animated' : ''}`,
|
|
70
|
+
background: colorScale(config.runtime.seriesLabels[bar.key]),
|
|
71
|
+
borderColor: '#333',
|
|
72
|
+
borderStyle: 'solid',
|
|
73
|
+
borderWidth: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px`,
|
|
74
|
+
width: bar.width,
|
|
75
|
+
height: bar.height,
|
|
76
|
+
x: bar.x,
|
|
77
|
+
y: bar.y,
|
|
78
|
+
onMouseOver: () => onMouseOverBar(yAxisValue, bar.key),
|
|
79
|
+
onMouseLeave: onMouseLeaveBar,
|
|
80
|
+
tooltipHtml: tooltip,
|
|
81
|
+
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
82
|
+
onClick: e => {
|
|
107
83
|
e.preventDefault()
|
|
108
84
|
if (setSharedFilter) {
|
|
109
85
|
bar[config.xAxis.dataKey] = xAxisValue
|
|
110
86
|
setSharedFilter(config.uid, bar)
|
|
111
87
|
}
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
88
|
+
},
|
|
89
|
+
styleOverrides: {
|
|
90
|
+
animationDelay: `${barStack.index * 0.5}s`,
|
|
91
|
+
transformOrigin: `${bar.x}px 0`,
|
|
92
|
+
opacity: transparentBar ? 0.2 : 1,
|
|
93
|
+
display: displayBar ? 'block' : 'none'
|
|
94
|
+
}
|
|
95
|
+
})}
|
|
116
96
|
|
|
117
97
|
{orientation === 'horizontal' && visualizationSubType === 'stacked' && isLabelBelowBar && barStack.index === 0 && !config.yAxis.hideLabel && (
|
|
118
98
|
<Text
|
|
@@ -6,12 +6,15 @@ import { Group } from '@visx/group'
|
|
|
6
6
|
import { Text } from '@visx/text'
|
|
7
7
|
import BarChartContext from './context'
|
|
8
8
|
import Regions from '../../Regions'
|
|
9
|
+
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
10
|
+
|
|
11
|
+
import createBarElement from '@cdc/core/components/createBarElement'
|
|
9
12
|
|
|
10
13
|
const BarChartStackedVertical = () => {
|
|
11
14
|
const [barWidth, setBarWidth] = useState(0)
|
|
12
15
|
const { xScale, yScale, xMax, yMax } = useContext(BarChartContext)
|
|
13
16
|
const { transformedData, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, setSharedFilter } = useContext(ConfigContext)
|
|
14
|
-
const { isHorizontal, barBorderWidth, applyRadius, hoveredBar, getAdditionalColumn, onMouseLeaveBar, onMouseOverBar } = useBarChart()
|
|
17
|
+
const { isHorizontal, barBorderWidth, applyRadius, hoveredBar, getAdditionalColumn, onMouseLeaveBar, onMouseOverBar, barStackedSeriesKeys } = useBarChart()
|
|
15
18
|
const { orientation } = config
|
|
16
19
|
const data = config.brush.active && config.brush.data?.length ? config.brush.data : transformedData
|
|
17
20
|
|
|
@@ -19,19 +22,21 @@ const BarChartStackedVertical = () => {
|
|
|
19
22
|
config.visualizationSubType === 'stacked' &&
|
|
20
23
|
!isHorizontal && (
|
|
21
24
|
<>
|
|
22
|
-
<BarStack data={data} keys={
|
|
25
|
+
<BarStack data={data} keys={barStackedSeriesKeys} x={d => d[config.runtime.xAxis.dataKey]} xScale={xScale} yScale={yScale} color={colorScale}>
|
|
23
26
|
{barStacks =>
|
|
24
27
|
barStacks.reverse().map(barStack =>
|
|
25
28
|
barStack.bars.map(bar => {
|
|
26
29
|
let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
|
|
27
30
|
let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
|
|
28
|
-
let barThickness = xMax / barStack.bars.length
|
|
29
|
-
let barThicknessAdjusted = barThickness * (config.barThickness || 0.8)
|
|
31
|
+
let barThickness = config.xAxis.type === 'date-time' ? config.barThickness * (xScale.range()[1] - xScale.range()[0]) : xMax / barStack.bars.length
|
|
32
|
+
let barThicknessAdjusted = barThickness * (config.xAxis.type === 'date-time' ? 1 : config.barThickness || 0.8)
|
|
30
33
|
let offset = (barThickness * (1 - (config.barThickness || 0.8))) / 2
|
|
31
34
|
// tooltips
|
|
32
|
-
const
|
|
35
|
+
const rawXValue = bar.bar.data[config.runtime.xAxis.dataKey]
|
|
36
|
+
const xAxisValue = config.runtime.xAxis.type === 'date' ? formatDate(parseDate(rawXValue)) : rawXValue
|
|
33
37
|
const yAxisValue = formatNumber(bar.bar ? bar.bar.data[bar.key] : 0, 'left')
|
|
34
38
|
if (!yAxisValue) return
|
|
39
|
+
const barX = xScale(config.runtime.xAxis.type === 'date' ? parseDate(rawXValue) : rawXValue) - (config.xAxis.type === 'date' && config.xAxis.sortDates ? barThicknessAdjusted / 2 : 0)
|
|
35
40
|
const style = applyRadius(barStack.index)
|
|
36
41
|
const xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
|
|
37
42
|
const additionalColTooltip = getAdditionalColumn(hoveredBar)
|
|
@@ -46,50 +51,40 @@ const BarChartStackedVertical = () => {
|
|
|
46
51
|
|
|
47
52
|
return (
|
|
48
53
|
<Group key={`${barStack.index}--${bar.index}--${orientation}`}>
|
|
49
|
-
<style>
|
|
50
|
-
{`
|
|
51
|
-
#barStack${barStack.index}-${bar.index} rect,
|
|
52
|
-
#barStack${barStack.index}-${bar.index} foreignObject div{
|
|
53
|
-
animation-delay: ${barStack.index * 0.5}s;
|
|
54
|
-
transform-origin: ${barThicknessAdjusted / 2}px ${bar.y + bar.height}px
|
|
55
|
-
}
|
|
56
|
-
`}
|
|
57
|
-
</style>
|
|
58
54
|
<Group key={`bar-stack-${barStack.index}-${bar.index}`} id={`barStack${barStack.index}-${bar.index}`} className='stack vertical'>
|
|
59
|
-
<Text display={config.labels && displayBar ? 'block' : 'none'} opacity={transparentBar ? 0.5 : 1} x={
|
|
55
|
+
<Text display={config.labels && displayBar ? 'block' : 'none'} opacity={transparentBar ? 0.5 : 1} x={barX + barWidth / 2} y={bar.y - 5} fill={'#000'} textAnchor='middle'>
|
|
60
56
|
{yAxisValue}
|
|
61
57
|
</Text>
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
58
|
+
{createBarElement({
|
|
59
|
+
config: config,
|
|
60
|
+
seriesHighlight,
|
|
61
|
+
index: barStack.index,
|
|
62
|
+
background: colorScale(config.runtime.seriesLabels[bar.key]),
|
|
63
|
+
borderColor: '#333',
|
|
64
|
+
borderStyle: 'solid',
|
|
65
|
+
borderWidth: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px`,
|
|
66
|
+
width: barThicknessAdjusted,
|
|
67
|
+
height: bar.height,
|
|
68
|
+
x: barX,
|
|
69
|
+
y: bar.y,
|
|
70
|
+
onMouseOver: () => onMouseOverBar(xAxisValue, bar.key),
|
|
71
|
+
onMouseLeave: onMouseLeaveBar,
|
|
72
|
+
tooltipHtml: tooltip,
|
|
73
|
+
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
74
|
+
onClick: e => {
|
|
74
75
|
e.preventDefault()
|
|
75
76
|
if (setSharedFilter) {
|
|
76
77
|
bar[config.xAxis.dataKey] = xAxisValue
|
|
77
78
|
setSharedFilter(config.uid, bar)
|
|
78
79
|
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
background: colorScale(config.runtime.seriesLabels[bar.key]),
|
|
88
|
-
border: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px solid #333`,
|
|
89
|
-
...style
|
|
90
|
-
}}
|
|
91
|
-
></div>
|
|
92
|
-
</foreignObject>
|
|
80
|
+
},
|
|
81
|
+
styleOverrides: {
|
|
82
|
+
animationDelay: `${barStack.index * 0.5}s`,
|
|
83
|
+
transformOrigin: `${barThicknessAdjusted / 2}px ${bar.y + bar.height}px`,
|
|
84
|
+
opacity: transparentBar ? 0.2 : 1,
|
|
85
|
+
display: displayBar ? 'block' : 'none'
|
|
86
|
+
}
|
|
87
|
+
})}
|
|
93
88
|
</Group>
|
|
94
89
|
</Group>
|
|
95
90
|
)
|