@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.
Files changed (60) hide show
  1. package/dist/cdcchart.js +47933 -36918
  2. package/examples/chart-regression-1.json +378 -0
  3. package/examples/chart-regression-2.json +2360 -0
  4. package/examples/feature/filters/url-filter.json +1076 -0
  5. package/examples/feature/line/line-chart.json +362 -37
  6. package/examples/feature/regions/index.json +50 -4
  7. package/examples/feature/sankey/sankey-example-data.json +1364 -0
  8. package/examples/feature/sankey/sankey_chart_data.csv +20 -0
  9. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +306 -19
  10. package/examples/region-issue.json +2065 -0
  11. package/examples/sparkline.json +868 -0
  12. package/examples/test.json +5409 -0
  13. package/index.html +130 -123
  14. package/package.json +4 -2
  15. package/src/CdcChart.tsx +178 -94
  16. package/src/_stories/ChartEditor.stories.tsx +14 -3
  17. package/src/_stories/_mock/url_filter.json +1076 -0
  18. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +2 -1
  19. package/src/components/AreaChart/components/AreaChart.jsx +2 -1
  20. package/src/components/BarChart/components/BarChart.Horizontal.tsx +46 -63
  21. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +36 -56
  22. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +32 -39
  23. package/src/components/BarChart/components/BarChart.Vertical.tsx +44 -59
  24. package/src/components/BoxPlot/BoxPlot.jsx +2 -1
  25. package/src/components/DeviationBar.jsx +3 -3
  26. package/src/components/EditorPanel/EditorPanel.tsx +1684 -1564
  27. package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +1 -1
  28. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +107 -0
  29. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +48 -4
  30. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +41 -0
  31. package/src/components/EditorPanel/components/Panels/index.tsx +9 -7
  32. package/src/components/EditorPanel/components/panels.scss +11 -0
  33. package/src/components/EditorPanel/editor-panel.scss +0 -724
  34. package/src/components/EditorPanel/useEditorPermissions.js +40 -14
  35. package/src/components/Legend/Legend.Component.tsx +43 -63
  36. package/src/components/Legend/Legend.tsx +8 -4
  37. package/src/components/LineChart/LineChartProps.ts +1 -0
  38. package/src/components/LineChart/helpers.ts +2 -2
  39. package/src/components/LineChart/index.tsx +7 -7
  40. package/src/components/LinearChart.jsx +11 -31
  41. package/src/components/PairedBarChart.jsx +6 -10
  42. package/src/components/PieChart/PieChart.tsx +3 -3
  43. package/src/components/Regions/components/Regions.tsx +120 -78
  44. package/src/components/Sankey/index.tsx +434 -0
  45. package/src/components/Sankey/sankey.scss +153 -0
  46. package/src/components/Sankey/types/index.ts +16 -0
  47. package/src/components/ScatterPlot/ScatterPlot.jsx +1 -0
  48. package/src/components/Sparkline/{SparkLine.jsx → components/SparkLine.tsx} +14 -30
  49. package/src/components/Sparkline/index.scss +3 -0
  50. package/src/components/Sparkline/index.tsx +1 -1
  51. package/src/components/ZoomBrush.tsx +2 -1
  52. package/src/data/initial-state.js +46 -2
  53. package/src/helpers/computeMarginBottom.ts +2 -1
  54. package/src/helpers/tests/computeMarginBottom.test.ts +2 -1
  55. package/src/hooks/useBarChart.js +5 -2
  56. package/src/hooks/useScales.ts +47 -18
  57. package/src/hooks/useTooltip.tsx +9 -8
  58. package/src/scss/main.scss +33 -29
  59. package/src/types/ChartConfig.ts +32 -14
  60. 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.type === 'date') {
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.type === 'date' ? xScale(parseDate(d[config.xAxis.dataKey], false)) : xScale(d[config.xAxis.dataKey])) + (xScale.bandwidth ? xScale.bandwidth() / 2 : 0)
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(yAxisValue)
134
- const highlightedBarColor = getHighlightedBarColorByValue(yAxisValue)
135
- const highlightedBar = getHighlightedBarByValue(yAxisValue)
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
- if (chroma.contrast(labelColor, barColor) < 4.9) {
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
- <foreignObject
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
- <div style={{ position: 'relative' }}>
219
- <div style={iconStyle}>{getIcon(bar, barWidth)}</div>
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={0 + lollipopBarWidth / 2}
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={config.runtime.barSeriesKeys || config.runtime.seriesKeys} height={yMax} y={d => d[config.runtime.yAxis.dataKey]} xScale={xScale} yScale={yScale} color={colorScale} offset='none'>
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
- let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
58
- let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
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
- let labelColor = '#000000'
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 style = applyRadius(barStack.index)
65
- let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
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
- <foreignObject
93
- onMouseOver={() => onMouseOverBar(yAxisValue, bar.key)}
94
- onMouseLeave={onMouseLeaveBar}
95
- key={`barstack-horizontal-${barStack.index}-${bar.index}-${index}`}
96
- className={`animated-chart group ${animatedChart ? 'animated' : ''}`}
97
- x={bar.x}
98
- y={bar.y}
99
- style={{ transition: 'all 0.2s linear' }}
100
- width={bar.width}
101
- height={bar.height}
102
- opacity={transparentBar ? 0.2 : 1}
103
- display={displayBar ? 'block' : 'none'}
104
- data-tooltip-html={tooltip}
105
- data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
106
- onClick={e => {
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
- <div style={{ width: bar.width, height: bar.height, background: colorScale(config.runtime.seriesLabels[bar.key]), border: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px solid #333`, ...style }}></div>
115
- </foreignObject>
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={config.runtime.barSeriesKeys || config.runtime.seriesKeys} x={d => d[config.runtime.xAxis.dataKey]} xScale={xScale} yScale={yScale} color={colorScale}>
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' && config.xAxis.sortDates ? (config.barThickness * (xScale.range()[1] - xScale.range()[0])) : xMax / barStack.bars.length
29
- let barThicknessAdjusted = barThickness * (config.xAxis.type === 'date' && config.xAxis.sortDates ? 1 : (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
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
- <foreignObject
65
- onMouseOver={() => onMouseOverBar(xAxisValue, bar.key)}
66
- onMouseLeave={onMouseLeaveBar}
67
- key={`bar-stack-${barStack.index}-${bar.index}`}
68
- x={barX}
69
- y={bar.y}
70
- width={barThicknessAdjusted}
71
- height={bar.height}
72
- display={displayBar ? 'block' : 'none'}
73
- data-tooltip-html={tooltip}
74
- data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
75
- onClick={e => {
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
- <div
84
- style={{
85
- transition: 'all 0.2s linear',
86
- opacity: transparentBar ? 0.2 : 1,
87
- width: barThicknessAdjusted,
88
- height: bar.height,
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.type === 'date' ? parseDate(rawXValue) : rawXValue
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 ? (((barGroupWidth / barGroup.bars.length) - lollipopBarWidth) / 2) : 0) - (config.xAxis.type === 'date' && config.xAxis.sortDates ? barGroupWidth / 2 : 0)
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 barColor
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 barColor
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 barColor
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
- <foreignObject
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
- <div style={{ position: 'relative' }}>
246
- <div style={iconStyle}>{getIcon(bar, barWidth)}</div>
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' || !config.xAxis.sortDates ? seriesScale.range()[1] / 2 : 0)
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 (
@@ -96,7 +96,8 @@ const CoveBoxPlot = ({ xScale, yScale }) => {
96
96
  container
97
97
  containerProps={{
98
98
  'data-tooltip-html': handleTooltip(d),
99
- 'data-tooltip-id': tooltip_id
99
+ 'data-tooltip-id': tooltip_id,
100
+ tabIndex: -1
100
101
  }}
101
102
  />
102
103
  </Group>