@cdc/chart 4.24.2 → 4.24.4
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 +47933 -36918
- package/examples/chart-regression-1.json +378 -0
- package/examples/chart-regression-2.json +2360 -0
- package/examples/feature/filters/url-filter.json +1076 -0
- package/examples/feature/line/line-chart.json +362 -37
- package/examples/feature/regions/index.json +50 -4
- 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/region-issue.json +2065 -0
- package/examples/sparkline.json +868 -0
- package/examples/test.json +5409 -0
- package/index.html +130 -123
- package/package.json +4 -2
- package/src/CdcChart.tsx +178 -94
- package/src/_stories/ChartEditor.stories.tsx +14 -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 -1
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +46 -63
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +36 -56
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +32 -39
- package/src/components/BarChart/components/BarChart.Vertical.tsx +44 -59
- package/src/components/BoxPlot/BoxPlot.jsx +2 -1
- package/src/components/DeviationBar.jsx +3 -3
- package/src/components/EditorPanel/EditorPanel.tsx +1684 -1564
- package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +1 -1
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +107 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +48 -4
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +41 -0
- package/src/components/EditorPanel/components/Panels/index.tsx +9 -7
- package/src/components/EditorPanel/components/panels.scss +11 -0
- package/src/components/EditorPanel/editor-panel.scss +0 -724
- package/src/components/EditorPanel/useEditorPermissions.js +40 -14
- package/src/components/Legend/Legend.Component.tsx +43 -63
- package/src/components/Legend/Legend.tsx +8 -4
- package/src/components/LineChart/LineChartProps.ts +1 -0
- package/src/components/LineChart/helpers.ts +2 -2
- package/src/components/LineChart/index.tsx +7 -7
- package/src/components/LinearChart.jsx +11 -31
- package/src/components/PairedBarChart.jsx +6 -10
- package/src/components/PieChart/PieChart.tsx +3 -3
- package/src/components/Regions/components/Regions.tsx +120 -78
- 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 +46 -2
- package/src/helpers/computeMarginBottom.ts +2 -1
- package/src/helpers/tests/computeMarginBottom.test.ts +2 -1
- package/src/hooks/useBarChart.js +5 -2
- package/src/hooks/useScales.ts +47 -18
- package/src/hooks/useTooltip.tsx +9 -8
- package/src/scss/main.scss +33 -29
- package/src/types/ChartConfig.ts +32 -14
- package/src/types/ChartContext.ts +7 -0
|
@@ -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'
|
|
@@ -19,7 +20,7 @@ const AreaChart = props => {
|
|
|
19
20
|
if (!data) return
|
|
20
21
|
|
|
21
22
|
const handleX = d => {
|
|
22
|
-
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)
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
const handleY = (d, index, s = undefined) => {
|
|
@@ -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,
|
|
@@ -76,6 +78,10 @@ export const BarChartHorizontal = () => {
|
|
|
76
78
|
let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
|
|
77
79
|
let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
|
|
78
80
|
let barHeight = config.barHeight
|
|
81
|
+
let numbericBarHeight = parseInt(!config.isLollipopChart ? barHeight : lollipopBarWidth)
|
|
82
|
+
if (isNaN(numbericBarHeight)) {
|
|
83
|
+
numbericBarHeight = 25
|
|
84
|
+
}
|
|
79
85
|
let barY = bar.value >= 0 && isNumber(bar.value) ? bar.y : yScale(scaleVal)
|
|
80
86
|
const barXBase = bar.value < 0 ? Math.abs(xScale(bar.value)) : xScale(scaleVal)
|
|
81
87
|
const barWidthHorizontal = Math.abs(xScale(bar.value) - xScale(scaleVal))
|
|
@@ -112,7 +118,6 @@ export const BarChartHorizontal = () => {
|
|
|
112
118
|
|
|
113
119
|
// create new Index for bars with negative values
|
|
114
120
|
const newIndex = bar.value < 0 ? -1 : index
|
|
115
|
-
const borderRadius = applyRadius(newIndex)
|
|
116
121
|
|
|
117
122
|
let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${xAxisValue}` : xAxisValue
|
|
118
123
|
const additionalColTooltip = getAdditionalColumn(hoveredBar)
|
|
@@ -130,39 +135,17 @@ export const BarChartHorizontal = () => {
|
|
|
130
135
|
barColor = assignColorsToValues(barGroups.length, barGroup.index, barColor) // Color code by category
|
|
131
136
|
const isRegularLollipopColor = config.isLollipopChart && config.lollipopColorStyle === 'regular'
|
|
132
137
|
const isTwoToneLollipopColor = config.isLollipopChart && config.lollipopColorStyle === 'two-tone'
|
|
133
|
-
const isHighlightedBar = highlightedBarValues?.includes(
|
|
134
|
-
const highlightedBarColor = getHighlightedBarColorByValue(
|
|
135
|
-
const highlightedBar = getHighlightedBarByValue(
|
|
138
|
+
const isHighlightedBar = highlightedBarValues?.includes(xAxisValue)
|
|
139
|
+
const highlightedBarColor = getHighlightedBarColorByValue(xAxisValue)
|
|
140
|
+
const highlightedBar = getHighlightedBarByValue(xAxisValue)
|
|
136
141
|
const borderColor = isHighlightedBar ? highlightedBarColor : config.barHasBorder === 'true' ? '#000' : 'transparent'
|
|
137
142
|
const borderWidth = isHighlightedBar ? highlightedBar.borderWidth : config.isLollipopChart ? 0 : config.barHasBorder === 'true' ? barBorderWidth : 0
|
|
138
143
|
const displaylollipopShape = config.suppressedData.some(d => bar.key === d.column && bar.value === d.value) ? 'none' : 'block'
|
|
139
144
|
// update label color
|
|
140
|
-
if (barColor && labelColor) {
|
|
141
|
-
|
|
142
|
-
labelColor = textFits ? '#FFFFFF' : '#000000'
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
const getTop = () => {
|
|
146
|
-
if (Number(barHeight) < 20) return -4
|
|
147
|
-
if (Number(barHeight) < 25) return -1
|
|
148
|
-
if (Number(barHeight) < 30) return 2
|
|
149
|
-
if (Number(barHeight) < 35) return 4
|
|
150
|
-
if (Number(barHeight) < 40) return 5
|
|
151
|
-
if (Number(barHeight) < 50) return 9
|
|
152
|
-
if (Number(barHeight) < 60) return 10
|
|
153
|
-
else {
|
|
154
|
-
return 12
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
const iconStyle: { [key: string]: any } = {
|
|
158
|
-
position: 'absolute',
|
|
159
|
-
top: getTop(),
|
|
160
|
-
left: suppresedBarWidth * 1.2
|
|
145
|
+
if (barColor && labelColor && textFits) {
|
|
146
|
+
labelColor = getContrastColor('#000', barColor)
|
|
161
147
|
}
|
|
162
148
|
|
|
163
|
-
if (config.isLollipopChart) {
|
|
164
|
-
iconStyle.top = -9
|
|
165
|
-
}
|
|
166
149
|
const background = () => {
|
|
167
150
|
if (isRegularLollipopColor) return barColor
|
|
168
151
|
if (isTwoToneLollipopColor) return chroma(barColor).brighten(1)
|
|
@@ -170,39 +153,42 @@ export const BarChartHorizontal = () => {
|
|
|
170
153
|
return barColor
|
|
171
154
|
}
|
|
172
155
|
|
|
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
156
|
return (
|
|
185
157
|
<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
158
|
<Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
|
|
196
|
-
|
|
159
|
+
{createBarElement({
|
|
160
|
+
config: config,
|
|
161
|
+
index: newIndex,
|
|
162
|
+
id: `barGroup${barGroup.index}`,
|
|
163
|
+
background: background(),
|
|
164
|
+
borderColor,
|
|
165
|
+
borderStyle: 'solid',
|
|
166
|
+
borderWidth: `${borderWidth}px`,
|
|
167
|
+
width: barWidth,
|
|
168
|
+
height: numbericBarHeight,
|
|
169
|
+
x: barX,
|
|
170
|
+
y: barHeight * bar.index,
|
|
171
|
+
onMouseOver: () => onMouseOverBar(xAxisValue, bar.key),
|
|
172
|
+
onMouseLeave: onMouseLeaveBar,
|
|
173
|
+
tooltipHtml: tooltip,
|
|
174
|
+
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
175
|
+
onClick: e => {
|
|
176
|
+
e.preventDefault()
|
|
177
|
+
if (setSharedFilter) {
|
|
178
|
+
bar[config.xAxis.dataKey] = yAxisValue
|
|
179
|
+
setSharedFilter(config.uid, bar)
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
styleOverrides: {
|
|
183
|
+
transformOrigin: `0 ${barY + barHeight}px`,
|
|
184
|
+
opacity: transparentBar ? 0.2 : 1,
|
|
185
|
+
display: displayBar ? 'block' : 'none'
|
|
186
|
+
}
|
|
187
|
+
})}
|
|
188
|
+
<g
|
|
189
|
+
transform={`translate(${barX},${barHeight * bar.index})`}
|
|
197
190
|
onMouseOver={() => onMouseOverBar(xAxisValue, bar.key)}
|
|
198
191
|
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
192
|
opacity={transparentBar ? 0.2 : 1}
|
|
207
193
|
display={displayBar ? 'block' : 'none'}
|
|
208
194
|
data-tooltip-html={tooltip}
|
|
@@ -215,11 +201,8 @@ export const BarChartHorizontal = () => {
|
|
|
215
201
|
}
|
|
216
202
|
}}
|
|
217
203
|
>
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
<div style={{ ...finalStyle }}></div>
|
|
221
|
-
</div>
|
|
222
|
-
</foreignObject>
|
|
204
|
+
{getIcon(bar, barWidth)}
|
|
205
|
+
</g>
|
|
223
206
|
|
|
224
207
|
{!config.isLollipopChart && displayNumbersOnBar && (
|
|
225
208
|
<Text // prettier-ignore
|
|
@@ -262,7 +245,7 @@ export const BarChartHorizontal = () => {
|
|
|
262
245
|
<circle
|
|
263
246
|
display={displaylollipopShape}
|
|
264
247
|
cx={bar.y}
|
|
265
|
-
cy={
|
|
248
|
+
cy={barHeight * bar.index + lollipopBarWidth / 2}
|
|
266
249
|
r={lollipopShapeSize / 2}
|
|
267
250
|
fill={barColor}
|
|
268
251
|
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,14 +22,14 @@ 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 = config.xAxis.type === 'date'
|
|
29
|
-
let barThicknessAdjusted = barThickness * (config.xAxis.type === 'date'
|
|
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
35
|
const rawXValue = bar.bar.data[config.runtime.xAxis.dataKey]
|
|
@@ -48,50 +51,40 @@ const BarChartStackedVertical = () => {
|
|
|
48
51
|
|
|
49
52
|
return (
|
|
50
53
|
<Group key={`${barStack.index}--${bar.index}--${orientation}`}>
|
|
51
|
-
<style>
|
|
52
|
-
{`
|
|
53
|
-
#barStack${barStack.index}-${bar.index} rect,
|
|
54
|
-
#barStack${barStack.index}-${bar.index} foreignObject div{
|
|
55
|
-
animation-delay: ${barStack.index * 0.5}s;
|
|
56
|
-
transform-origin: ${barThicknessAdjusted / 2}px ${bar.y + bar.height}px
|
|
57
|
-
}
|
|
58
|
-
`}
|
|
59
|
-
</style>
|
|
60
54
|
<Group key={`bar-stack-${barStack.index}-${bar.index}`} id={`barStack${barStack.index}-${bar.index}`} className='stack vertical'>
|
|
61
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'>
|
|
62
56
|
{yAxisValue}
|
|
63
57
|
</Text>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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 => {
|
|
76
75
|
e.preventDefault()
|
|
77
76
|
if (setSharedFilter) {
|
|
78
77
|
bar[config.xAxis.dataKey] = xAxisValue
|
|
79
78
|
setSharedFilter(config.uid, bar)
|
|
80
79
|
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
background: colorScale(config.runtime.seriesLabels[bar.key]),
|
|
90
|
-
border: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px solid #333`,
|
|
91
|
-
...style
|
|
92
|
-
}}
|
|
93
|
-
></div>
|
|
94
|
-
</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
|
+
})}
|
|
95
88
|
</Group>
|
|
96
89
|
</Group>
|
|
97
90
|
)
|
|
@@ -8,6 +8,9 @@ import { BarGroup } from '@visx/shape'
|
|
|
8
8
|
import { useHighlightedBars } from '../../../hooks/useHighlightedBars'
|
|
9
9
|
import { FaStar } from 'react-icons/fa'
|
|
10
10
|
import Regions from './../../Regions'
|
|
11
|
+
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
12
|
+
|
|
13
|
+
import createBarElement from '@cdc/core/components/createBarElement'
|
|
11
14
|
|
|
12
15
|
// third party
|
|
13
16
|
import chroma from 'chroma-js'
|
|
@@ -75,7 +78,7 @@ export const BarChartVertical = () => {
|
|
|
75
78
|
height={yMax}
|
|
76
79
|
x0={d => {
|
|
77
80
|
const rawXValue = d[config.runtime.originalXAxis.dataKey]
|
|
78
|
-
return config.runtime.xAxis
|
|
81
|
+
return isDateScale(config.runtime.xAxis) ? parseDate(rawXValue) : rawXValue
|
|
79
82
|
}}
|
|
80
83
|
x0Scale={xScale}
|
|
81
84
|
x1Scale={seriesScale}
|
|
@@ -102,7 +105,7 @@ export const BarChartVertical = () => {
|
|
|
102
105
|
let barGroupWidth = seriesScale.range()[1]
|
|
103
106
|
|
|
104
107
|
let barWidth = config.isLollipopChart ? lollipopBarWidth : barGroupWidth / barGroup.bars.length
|
|
105
|
-
let barX = bar.x + (config.isLollipopChart ? (
|
|
108
|
+
let barX = bar.x + (config.isLollipopChart ? (barGroupWidth / barGroup.bars.length - lollipopBarWidth) / 2 : 0) - (config.xAxis.type === 'date-time' ? barGroupWidth / 2 : 0)
|
|
106
109
|
setBarWidth(barWidth)
|
|
107
110
|
setTotalBarsInGroup(barGroup.bars.length)
|
|
108
111
|
|
|
@@ -111,7 +114,6 @@ export const BarChartVertical = () => {
|
|
|
111
114
|
|
|
112
115
|
// create new Index for bars with negative values
|
|
113
116
|
const newIndex = bar.value < 0 ? -1 : index
|
|
114
|
-
const borderRadius = applyRadius(newIndex)
|
|
115
117
|
// tooltips
|
|
116
118
|
|
|
117
119
|
const additionalColTooltip = getAdditionalColumn(bar.key, data[barGroup.index][config.runtime.originalXAxis.dataKey])
|
|
@@ -149,19 +151,19 @@ export const BarChartVertical = () => {
|
|
|
149
151
|
* color the bar that is using the filter with barColor and
|
|
150
152
|
* color the filteredOut (typically gray) bars with the filteredOutColor
|
|
151
153
|
*/
|
|
152
|
-
if (dashboardConfig && dashboardConfig.dashboard.sharedFilters) {
|
|
154
|
+
if (dashboardConfig && dashboardConfig.dashboard.sharedFilters?.length !== 0) {
|
|
153
155
|
const { sharedFilters } = dashboardConfig.dashboard
|
|
154
156
|
|
|
155
157
|
_barColor = sharedFilters.map(_sharedFilter => {
|
|
156
158
|
if (_sharedFilter.setBy === config.uid) {
|
|
157
159
|
// If the current filter is the reset filter item.
|
|
158
|
-
if (_sharedFilter.resetLabel === _sharedFilter.active) return
|
|
160
|
+
if (_sharedFilter.resetLabel === _sharedFilter.active) return colorScale(config.runtime.seriesLabels[bar.key])
|
|
159
161
|
// If the current filter is the bars
|
|
160
|
-
if (_sharedFilter.active === transformedData[barGroup.index][config.xAxis.dataKey]) return
|
|
162
|
+
if (_sharedFilter.active === transformedData[barGroup.index][config.xAxis.dataKey]) return colorScale(config.runtime.seriesLabels[bar.key])
|
|
161
163
|
return _filteredOutColor
|
|
162
164
|
} else {
|
|
163
165
|
// If the setBy isn't the config.uid return the original barColor
|
|
164
|
-
return
|
|
166
|
+
return colorScale(config.runtime.seriesLabels[bar.key])
|
|
165
167
|
}
|
|
166
168
|
})[0]
|
|
167
169
|
|
|
@@ -179,57 +181,43 @@ export const BarChartVertical = () => {
|
|
|
179
181
|
return _barColor
|
|
180
182
|
}
|
|
181
183
|
|
|
182
|
-
const getLeft = () => {
|
|
183
|
-
if (barWidth < 50 && barWidth > 15) return barWidth / 2.5
|
|
184
|
-
if (barWidth < 15 && barWidth > 5) return barWidth / 6
|
|
185
|
-
if (barWidth < 5) return 0
|
|
186
|
-
return barWidth / 2
|
|
187
|
-
}
|
|
188
|
-
const iconStyle: { [key: string]: any } = {
|
|
189
|
-
position: 'absolute',
|
|
190
|
-
top: bar.value >= 0 && isNumber(bar.value) ? -suppresedBarHeight : undefined,
|
|
191
|
-
bottom: bar.value >= 0 && isNumber(bar.value) ? undefined : `-${suppresedBarHeight}px`,
|
|
192
|
-
left: getLeft()
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (config.isLollipopChart) {
|
|
196
|
-
iconStyle.left = 0
|
|
197
|
-
iconStyle.transform = `translateX(0)`
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
const finalStyle = {
|
|
201
|
-
background: getBarBackgroundColor(barColor),
|
|
202
|
-
borderColor,
|
|
203
|
-
borderStyle: 'solid',
|
|
204
|
-
borderWidth: `${borderWidth}px`,
|
|
205
|
-
width: barWidth,
|
|
206
|
-
height: barHeight,
|
|
207
|
-
...borderRadius,
|
|
208
|
-
cursor: dashboardConfig ? 'pointer' : 'default'
|
|
209
|
-
}
|
|
210
|
-
|
|
211
184
|
return (
|
|
212
185
|
<Group key={`${barGroup.index}--${index}`}>
|
|
213
|
-
{/* This feels gross but inline transition was not working well*/}
|
|
214
|
-
<style>
|
|
215
|
-
{`
|
|
216
|
-
.linear #barGroup${barGroup.index} div,
|
|
217
|
-
.Combo #barGroup${barGroup.index} div {
|
|
218
|
-
transform-origin: 0 ${barY + barHeight}px;
|
|
219
|
-
}
|
|
220
|
-
`}
|
|
221
|
-
</style>
|
|
222
186
|
<Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
|
|
223
|
-
|
|
187
|
+
{createBarElement({
|
|
188
|
+
config: config,
|
|
189
|
+
index: newIndex,
|
|
190
|
+
id: `barGroup${barGroup.index}`,
|
|
191
|
+
background: getBarBackgroundColor(colorScale(config.runtime.seriesLabels[bar.key])),
|
|
192
|
+
borderColor,
|
|
193
|
+
borderStyle: 'solid',
|
|
194
|
+
borderWidth: `${borderWidth}px`,
|
|
195
|
+
width: barWidth,
|
|
196
|
+
height: barHeight,
|
|
197
|
+
x: barX,
|
|
198
|
+
y: barY,
|
|
199
|
+
onMouseOver: () => onMouseOverBar(xAxisValue, bar.key),
|
|
200
|
+
onMouseLeave: onMouseLeaveBar,
|
|
201
|
+
tooltipHtml: tooltip,
|
|
202
|
+
tooltipId: `cdc-open-viz-tooltip-${config.runtime.uniqueId}`,
|
|
203
|
+
onClick: e => {
|
|
204
|
+
e.preventDefault()
|
|
205
|
+
if (setSharedFilter) {
|
|
206
|
+
bar[config.xAxis.dataKey] = xAxisValue
|
|
207
|
+
setSharedFilter(config.uid, bar)
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
styleOverrides: {
|
|
211
|
+
transformOrigin: `0 ${barY + barHeight}px`,
|
|
212
|
+
opacity: transparentBar ? 0.2 : 1,
|
|
213
|
+
display: displayBar ? 'block' : 'none',
|
|
214
|
+
cursor: dashboardConfig ? 'pointer' : 'default'
|
|
215
|
+
}
|
|
216
|
+
})}
|
|
217
|
+
<g
|
|
218
|
+
transform={`translate(${barX},${yMax - suppresedBarHeight})`}
|
|
224
219
|
onMouseOver={() => onMouseOverBar(xAxisValue, bar.key)}
|
|
225
220
|
onMouseLeave={onMouseLeaveBar}
|
|
226
|
-
style={{ overflow: 'visible', transition: 'all 0.2s linear' }}
|
|
227
|
-
id={`barGroup${barGroup.index}`}
|
|
228
|
-
key={`bar-group-bar-${barGroup.index}-${bar.index}-${bar.value}-${bar.key}`}
|
|
229
|
-
x={barX}
|
|
230
|
-
y={barY}
|
|
231
|
-
width={barWidth}
|
|
232
|
-
height={barHeight}
|
|
233
221
|
opacity={transparentBar ? 0.2 : 1}
|
|
234
222
|
display={displayBar ? 'block' : 'none'}
|
|
235
223
|
data-tooltip-html={tooltip}
|
|
@@ -242,11 +230,8 @@ export const BarChartVertical = () => {
|
|
|
242
230
|
}
|
|
243
231
|
}}
|
|
244
232
|
>
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
<div style={{ ...finalStyle }}></div>
|
|
248
|
-
</div>
|
|
249
|
-
</foreignObject>
|
|
233
|
+
{getIcon(bar, barWidth)}
|
|
234
|
+
</g>
|
|
250
235
|
|
|
251
236
|
<Text // prettier-ignore
|
|
252
237
|
display={config.labels && displayBar ? 'block' : 'none'}
|
|
@@ -303,7 +288,7 @@ export const BarChartVertical = () => {
|
|
|
303
288
|
let upperPos
|
|
304
289
|
let lowerPos
|
|
305
290
|
let tickWidth = 5
|
|
306
|
-
xPos = xScale(getXAxisData(d)) + (config.xAxis.type !== 'date' ||
|
|
291
|
+
xPos = xScale(getXAxisData(d)) + (config.xAxis.type !== 'date' || config.xAxis.type !== 'date-time' ? seriesScale.range()[1] / 2 : 0)
|
|
307
292
|
upperPos = yScale(getYAxisData(d, config.confidenceKeys.lower))
|
|
308
293
|
lowerPos = yScale(getYAxisData(d, config.confidenceKeys.upper))
|
|
309
294
|
return (
|