@cdc/chart 4.23.10 → 4.23.11

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 (56) hide show
  1. package/dist/cdcchart.js +30989 -29057
  2. package/examples/feature/bar/example-bar-chart.json +1 -46
  3. package/examples/feature/bar/lollipop.json +156 -0
  4. package/examples/feature/combo/planet-combo-example-config.json +99 -9
  5. package/examples/feature/dev-4261.json +399 -0
  6. package/examples/feature/forest-plot/{broken.json → linear.json} +55 -50
  7. package/examples/feature/forest-plot/logarithmic.json +306 -0
  8. package/examples/feature/line/line-points.json +340 -0
  9. package/examples/feature/regions/index.json +462 -0
  10. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +181 -48
  11. package/examples/sparkline-multilple.json +846 -0
  12. package/index.html +10 -6
  13. package/package.json +3 -3
  14. package/src/CdcChart.tsx +75 -63
  15. package/src/_stories/Chart.stories.tsx +188 -0
  16. package/src/_stories/Chart.tooltip.stories.tsx +305 -0
  17. package/src/_stories/ChartBrush.stories.tsx +19 -0
  18. package/src/_stories/ChartSuppress.stories.tsx +19 -0
  19. package/src/_stories/_mock/brush_mock.json +393 -0
  20. package/src/_stories/_mock/suppress_mock.json +911 -0
  21. package/src/components/AreaChart.Stacked.jsx +4 -5
  22. package/src/components/AreaChart.jsx +6 -35
  23. package/src/components/{BarChart.Horizontal.jsx → BarChart.Horizontal.tsx} +106 -29
  24. package/src/components/{BarChart.StackedHorizontal.jsx → BarChart.StackedHorizontal.tsx} +22 -17
  25. package/src/components/{BarChart.StackedVertical.jsx → BarChart.StackedVertical.tsx} +22 -26
  26. package/src/components/{BarChart.Vertical.jsx → BarChart.Vertical.tsx} +175 -31
  27. package/src/components/BarChart.jsx +1 -1
  28. package/src/components/DeviationBar.jsx +4 -3
  29. package/src/components/EditorPanel.jsx +176 -50
  30. package/src/components/ForestPlot/ForestPlotProps.ts +11 -0
  31. package/src/components/ForestPlot/Readme.md +0 -0
  32. package/src/components/ForestPlot/index.scss +1 -0
  33. package/src/components/{ForestPlot.jsx → ForestPlot/index.tsx} +51 -31
  34. package/src/components/ForestPlotSettings.jsx +162 -113
  35. package/src/components/Legend.jsx +36 -3
  36. package/src/components/{LineChart.Circle.tsx → LineChart/LineChart.Circle.tsx} +26 -29
  37. package/src/components/LineChart/LineChartProps.ts +17 -0
  38. package/src/components/LineChart/index.scss +1 -0
  39. package/src/components/{LineChart.tsx → LineChart/index.tsx} +64 -35
  40. package/src/components/LinearChart.jsx +120 -60
  41. package/src/components/PairedBarChart.jsx +2 -2
  42. package/src/components/Series.jsx +22 -3
  43. package/src/components/ZoomBrush.tsx +168 -0
  44. package/src/data/initial-state.js +27 -12
  45. package/src/hooks/useBarChart.js +71 -7
  46. package/src/hooks/useColorScale.ts +50 -0
  47. package/src/hooks/useEditorPermissions.js +22 -4
  48. package/src/hooks/{useMinMax.js → useMinMax.ts} +75 -23
  49. package/src/hooks/{useRightAxis.js → useRightAxis.ts} +10 -2
  50. package/src/hooks/{useScales.js → useScales.ts} +64 -17
  51. package/src/hooks/useTooltip.jsx +68 -41
  52. package/src/scss/main.scss +3 -35
  53. package/src/types/ChartConfig.ts +43 -0
  54. package/src/types/ChartContext.ts +38 -0
  55. package/src/types/ChartProps.ts +7 -0
  56. package/src/types/ForestPlot.ts +60 -0
@@ -10,10 +10,10 @@ import { Bar, AreaStack } from '@visx/shape'
10
10
  import { Group } from '@visx/group'
11
11
  import { approvedCurveTypes } from '@cdc/core/helpers/lineChartHelpers'
12
12
 
13
- const AreaChartStacked = ({ xScale, yScale, yMax, xMax, handleTooltipMouseOver, handleTooltipMouseOff, isDebug, isBrush }) => {
13
+ const AreaChartStacked = ({ xScale, yScale, yMax, xMax, handleTooltipMouseOver, handleTooltipMouseOff, isDebug }) => {
14
14
  // import data from context
15
- let { transformedData: data, config, seriesHighlight, colorScale, rawData } = useContext(ConfigContext)
16
-
15
+ let { transformedData, config, seriesHighlight, colorScale, rawData } = useContext(ConfigContext)
16
+ const data = config.brush.active && config.brush.data?.length ? config.brush.data : transformedData
17
17
  // Draw transparent bars over the chart to get tooltip data
18
18
  // Turn DEBUG on for additional context.
19
19
  if (!data) return
@@ -60,9 +60,8 @@ const AreaChartStacked = ({ xScale, yScale, yMax, xMax, handleTooltipMouseOver,
60
60
  })
61
61
  }}
62
62
  </AreaStack>
63
-
64
63
  {/* prettier-ignore */}
65
- {!isBrush && <Bar width={Number(xMax)} height={Number(yMax)} fill={isDebug ? 'red' : 'transparent'} fillOpacity={0.05} style={isDebug ? { stroke: 'black', strokeWidth: 2 } : {}} onMouseMove={e => handleTooltipMouseOver(e, rawData)} onMouseLeave={handleTooltipMouseOff} />}
64
+ <Bar width={Number(xMax)} height={Number(yMax)} fill={'transparent'} onMouseMove={e => handleTooltipMouseOver(e, rawData)} onMouseLeave={handleTooltipMouseOff} />
66
65
  </Group>
67
66
  </ErrorBoundary>
68
67
  </svg>
@@ -11,17 +11,11 @@ import { Group } from '@visx/group'
11
11
  import { bisector } from 'd3-array'
12
12
 
13
13
  const AreaChart = props => {
14
- const { xScale, yScale, yMax, xMax, handleTooltipMouseOver, handleTooltipMouseOff, isDebug, isBrush, brushData, children } = props
14
+ const { xScale, yScale, yMax, xMax, handleTooltipMouseOver, handleTooltipMouseOff, isDebug, children } = props
15
15
  // import data from context
16
- let { transformedData: data, config, handleLineType, parseDate, formatDate, formatNumber, seriesHighlight, colorScale, rawData } = useContext(ConfigContext)
16
+ let { transformedData, config, handleLineType, parseDate, formatDate, formatNumber, seriesHighlight, colorScale, rawData } = useContext(ConfigContext)
17
+ const data = config.brush.active && config.brush.data?.length ? config.brush.data : transformedData
17
18
 
18
- // use brush data if it is passed in AND if this is NOT a brush chart
19
- data = !isBrush && undefined !== brushData && brushData.length ? brushData : data
20
-
21
- if (isBrush && isDebug) console.log('###AREAchart BRUSH data, xScale, yScale, yMax, xMax', data, xScale, yScale, yMax, xMax)
22
-
23
- // Draw transparent bars over the chart to get tooltip data
24
- // Turn isDebug on for additional context.
25
19
  if (!data) return
26
20
 
27
21
  // Tooltip helper for getting data to the closest date/category hovered.
@@ -42,38 +36,19 @@ const AreaChart = props => {
42
36
  }
43
37
  }
44
38
 
45
- const getXAxisDates = brushDataSet => {
46
- if (undefined === brushDataSet || !brushDataSet) return
47
- let XAxisBrushDates = []
48
- brushDataSet.forEach(function convertDateTimeNumber(key, value, brushDataSet) {
49
- let tmp = getXValueFromCoordinate(xScale(value))
50
- let date = formatDate(tmp)
51
- XAxisBrushDates.push(date)
52
- })
53
- return XAxisBrushDates
54
- }
55
-
56
39
  const handleX = d => {
57
40
  return config.xAxis.type === 'date' ? xScale(parseDate(d[config.xAxis.dataKey], false)) : xScale(d[config.xAxis.dataKey])
58
41
  }
59
42
 
60
43
  const handleY = (d, index, s = undefined) => {
61
- return isBrush ? yScale(d[s.dataKey]) / 4 : yScale(d[s.dataKey])
62
- }
63
-
64
- // prevents duplicate brush handles being rendered
65
- const getFirstBrushHandleOnly = (children, index) => {
66
- if (index === 0) {
67
- return children
68
- }
69
- // else dont return the other brush handles
44
+ return yScale(d[s.dataKey])
70
45
  }
71
46
 
72
47
  return (
73
48
  data && (
74
49
  <svg>
75
50
  <ErrorBoundary component='AreaChart'>
76
- <Group className='area-chart' key='area-wrapper' left={Number(config.yAxis.size)} top={isBrush ? yMax * 1.3 : 0}>
51
+ <Group className='area-chart' key='area-wrapper' left={Number(config.yAxis.size)}>
77
52
  {(config.runtime.areaSeriesKeys || config.series).map((s, index) => {
78
53
  let seriesData = data.map(d => {
79
54
  return {
@@ -119,14 +94,10 @@ const AreaChart = props => {
119
94
  curve={curveType}
120
95
  strokeDasharray={s.type ? handleLineType(s.type) : 0}
121
96
  />
122
- {getFirstBrushHandleOnly(children, index)}
123
97
  </React.Fragment>
124
98
  )
125
99
  })}
126
-
127
- {/* Transparent bar for tooltips - disable if AreaChart is a brush */}
128
- {/* prettier-ignore */}
129
- {!isBrush && <Bar width={Number(xMax)} height={Number(yMax)} fill={isDebug ? 'red' : 'transparent'} fillOpacity={0.05} style={isDebug ? { stroke: 'black', strokeWidth: 2 } : {}} onMouseMove={e => handleTooltipMouseOver(e, rawData)} onMouseLeave={handleTooltipMouseOff} />}
100
+ <Bar width={Number(xMax)} height={Number(yMax)} fill={'transparent'} fillOpacity={0.05} onMouseMove={e => handleTooltipMouseOver(e, rawData)} onMouseLeave={handleTooltipMouseOff} />
130
101
  </Group>
131
102
  </ErrorBoundary>
132
103
  </svg>
@@ -5,17 +5,49 @@ import { Group } from '@visx/group'
5
5
  import { Text } from '@visx/text'
6
6
  import { BarGroup } from '@visx/shape'
7
7
  import { useHighlightedBars } from '../hooks/useHighlightedBars'
8
+ import { FaStar } from 'react-icons/fa'
8
9
 
9
10
  // third party
10
11
  import chroma from 'chroma-js'
11
12
 
12
- export const BarChartHorizontal = props => {
13
+ import { type BarChartProps } from '../types/ChartProps'
14
+
15
+ export const BarChartHorizontal = (props: BarChartProps) => {
13
16
  const { xScale, yScale, yMax, seriesScale } = props
14
17
  const { transformedData: data, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, setSharedFilter, isNumber, getTextWidth, getYAxisData, getXAxisData } = useContext(ConfigContext)
15
- const { isHorizontal, barBorderWidth, hasMultipleSeries, applyRadius, updateBars, assignColorsToValues, section, fontSize, isLabelBelowBar, displayNumbersOnBar, lollipopBarWidth, lollipopShapeSize, getHighlightedBarColorByValue, getHighlightedBarByValue } = useBarChart()
18
+ const {
19
+ isHorizontal,
20
+ barBorderWidth,
21
+ applyRadius,
22
+ updateBars,
23
+ assignColorsToValues,
24
+ section,
25
+ fontSize,
26
+ isLabelBelowBar,
27
+ displayNumbersOnBar,
28
+ lollipopBarWidth,
29
+ lollipopShapeSize,
30
+ getHighlightedBarColorByValue,
31
+ getHighlightedBarByValue,
32
+ generateIconSize,
33
+ getAdditionalColumn,
34
+ hoveredBar,
35
+ onMouseLeaveBar,
36
+ onMouseOverBar
37
+ } = useBarChart()
16
38
 
17
39
  const { HighLightedBarUtils } = useHighlightedBars(config)
18
-
40
+ const getIcon = (bar, barWidth) => {
41
+ let icon = null
42
+ const iconSize = generateIconSize(barWidth)
43
+ config.suppressedData?.forEach(d => {
44
+ if (bar.key === d.column && String(bar.value) === String(d.value) && d.icon) {
45
+ icon = <FaStar color='#000' size={iconSize} />
46
+ // icon = <BarIcon color='#000' size={fontSize[config.fontSize] / 1.7} />
47
+ }
48
+ })
49
+ return icon
50
+ }
19
51
  return (
20
52
  config.visualizationSubType !== 'stacked' &&
21
53
  config.visualizationType === 'Bar' &&
@@ -40,21 +72,24 @@ export const BarChartHorizontal = props => {
40
72
  const scaleVal = config.useLogScale ? 0.1 : 0
41
73
 
42
74
  let highlightedBarValues = config.highlightedBarValues.map(item => item.value).filter(item => item !== ('' || undefined))
43
-
44
75
  highlightedBarValues = config.xAxis.type === 'date' ? HighLightedBarUtils.formatDates(highlightedBarValues) : highlightedBarValues
45
-
46
76
  let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
47
77
  let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
48
78
  let barHeight = config.barHeight
49
- let barY = bar.value >= 0 && isNumber(bar.value) ? bar.y : yScale(0)
50
- const barX = bar.value < 0 ? Math.abs(xScale(bar.value)) : xScale(0)
79
+ let barY = bar.value >= 0 && isNumber(bar.value) ? bar.y : yScale(scaleVal)
80
+ const barXBase = bar.value < 0 ? Math.abs(xScale(bar.value)) : xScale(scaleVal)
51
81
  const barWidthHorizontal = Math.abs(xScale(bar.value) - xScale(scaleVal))
52
- const barWidth = config.barHeight
82
+ const suppresedBarWidth = 25
83
+ const isPositiveBar = bar.value >= 0 && isNumber(bar.value)
84
+ let barWidth = bar.value && config.suppressedData.some(({ column, value }) => bar.key === column && bar.value === value) ? suppresedBarWidth : barWidthHorizontal
53
85
 
86
+ const supprssedBarX = isPositiveBar ? xScale(0) : xScale(scaleVal) - suppresedBarWidth
87
+ const barX = config.suppressedData.some(d => bar.key === d.column && String(bar.value) === String(d.value)) ? supprssedBarX : barXBase
54
88
  const yAxisValue = formatNumber(bar.value, 'left')
55
89
  const xAxisValue = config.runtime[section].type === 'date' ? formatDate(parseDate(data[barGroup.index][config.runtime.originalXAxis.dataKey])) : data[barGroup.index][config.runtime.originalXAxis.dataKey]
56
90
 
57
- const barPosition = bar.value < 0 ? 'below' : 'above'
91
+ const barPosition = !isPositiveBar ? 'below' : 'above'
92
+ const barValueLabel = config.suppressedData.some(d => bar.key === d.column && bar.value === d.value) ? '' : yAxisValue
58
93
 
59
94
  // check if bar text/value string fits into each bars.
60
95
  let textWidth = getTextWidth(xAxisValue, `normal ${fontSize[config.fontSize]}px sans-serif`)
@@ -79,16 +114,13 @@ export const BarChartHorizontal = props => {
79
114
  const newIndex = bar.value < 0 ? -1 : index
80
115
  const borderRadius = applyRadius(newIndex)
81
116
 
82
- let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
83
- let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
84
- if (!hasMultipleSeries) {
85
- xAxisTooltip = config.isLegendValue ? `<p className="tooltip-heading">${bar.key}: ${xAxisValue}</p>` : config.runtime.xAxis.label ? `<p className="tooltip-heading">${config.runtime.xAxis.label}: ${xAxisValue}</p>` : xAxisValue
86
- }
87
-
117
+ let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${xAxisValue}` : xAxisValue
118
+ const additionalColTooltip = getAdditionalColumn(hoveredBar)
119
+ const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${yAxisValue}`
88
120
  const tooltip = `<ul>
89
- ${config.legend.showLegendValuesTooltip && config.runtime.seriesLabels && hasMultipleSeries ? `${config.runtime.seriesLabels[bar.key] || ''}<br/>` : ''}
90
- <li class="tooltip-heading">${yAxisTooltip}</li>
91
- <li class="tooltip-body">${xAxisTooltip}</li>
121
+ <li class="tooltip-heading"">${yAxisTooltip}</li>
122
+ <li class="tooltip-body ">${tooltipBody}</li>
123
+ <li class="tooltip-body ">${additionalColTooltip}</li>
92
124
  </li></ul>`
93
125
 
94
126
  // configure colors
@@ -103,23 +135,49 @@ export const BarChartHorizontal = props => {
103
135
  const highlightedBar = getHighlightedBarByValue(yAxisValue)
104
136
  const borderColor = isHighlightedBar ? highlightedBarColor : config.barHasBorder === 'true' ? '#000' : 'transparent'
105
137
  const borderWidth = isHighlightedBar ? highlightedBar.borderWidth : config.isLollipopChart ? 0 : config.barHasBorder === 'true' ? barBorderWidth : 0
138
+ const displaylollipopShape = config.suppressedData.some(d => bar.key === d.column && bar.value === d.value) ? 'none' : 'block'
106
139
  // update label color
107
140
  if (barColor && labelColor) {
108
141
  if (chroma.contrast(labelColor, barColor) < 4.9) {
109
142
  labelColor = textFits ? '#FFFFFF' : '#000000'
110
143
  }
111
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
161
+ }
162
+
163
+ if (config.isLollipopChart) {
164
+ iconStyle.top = -9
165
+ }
112
166
  const background = () => {
113
167
  if (isRegularLollipopColor) return barColor
114
168
  if (isTwoToneLollipopColor) return chroma(barColor).brighten(1)
115
169
  if (isHighlightedBar) return 'transparent'
116
170
  return barColor
117
171
  }
172
+
118
173
  const finalStyle = {
119
174
  background: background(),
120
175
  borderColor,
121
176
  borderStyle: 'solid',
122
177
  borderWidth,
178
+ width: barWidth,
179
+ transition: 'all 0.2s linear',
180
+ height: !config.isLollipopChart ? barHeight : lollipopBarWidth,
123
181
  ...borderRadius
124
182
  }
125
183
 
@@ -128,22 +186,24 @@ export const BarChartHorizontal = props => {
128
186
  {/* This feels gross but inline transition was not working well*/}
129
187
  <style>
130
188
  {`
131
- .linear #barGroup${barGroup.index},
132
- .Combo #barGroup${barGroup.index} {
189
+ .linear #barGroup${barGroup.index} div,
190
+ .Combo #barGroup${barGroup.index} div {
133
191
  transform-origin: 0 ${barY + barHeight}px;
134
192
  }
135
193
  `}
136
194
  </style>
137
195
  <Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
138
196
  <foreignObject
197
+ onMouseOver={() => onMouseOverBar(xAxisValue, bar.key)}
198
+ onMouseLeave={onMouseLeaveBar}
139
199
  id={`barGroup${barGroup.index}`}
140
200
  key={`bar-group-bar-${barGroup.index}-${bar.index}-${bar.value}-${bar.key}`}
141
201
  x={barX}
142
- y={barWidth * bar.index}
143
- width={barWidthHorizontal}
144
- height={!config.isLollipopChart ? barWidth : lollipopBarWidth}
145
- style={finalStyle}
146
- opacity={transparentBar ? 0.5 : 1}
202
+ style={{ overflow: 'visible', ...finalStyle }}
203
+ y={barHeight * bar.index}
204
+ height={!config.isLollipopChart ? barHeight : lollipopBarWidth}
205
+ width={barWidth}
206
+ opacity={transparentBar ? 0.2 : 1}
147
207
  display={displayBar ? 'block' : 'none'}
148
208
  data-tooltip-html={tooltip}
149
209
  data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
@@ -154,7 +214,13 @@ export const BarChartHorizontal = props => {
154
214
  setSharedFilter(config.uid, bar)
155
215
  }
156
216
  }}
157
- ></foreignObject>
217
+ >
218
+ <div style={{ position: 'relative' }}>
219
+ <div style={iconStyle}>{getIcon(bar, barWidth)}</div>
220
+ <div style={{ ...finalStyle }}></div>
221
+ </div>
222
+ </foreignObject>
223
+
158
224
  {!config.isLollipopChart && displayNumbersOnBar && (
159
225
  <Text // prettier-ignore
160
226
  display={displayBar ? 'block' : 'none'}
@@ -165,7 +231,7 @@ export const BarChartHorizontal = props => {
165
231
  verticalAnchor='middle'
166
232
  textAnchor={textAnchor}
167
233
  >
168
- {yAxisValue}
234
+ {barValueLabel}
169
235
  </Text>
170
236
  )}
171
237
  {config.isLollipopChart && displayNumbersOnBar && (
@@ -179,7 +245,7 @@ export const BarChartHorizontal = props => {
179
245
  verticalAnchor='middle'
180
246
  fontWeight={'normal'}
181
247
  >
182
- {yAxisValue}
248
+ {barValueLabel}
183
249
  </Text>
184
250
  )}
185
251
  {isLabelBelowBar && !config.yAxis.hideLabel && (
@@ -193,10 +259,21 @@ export const BarChartHorizontal = props => {
193
259
  )}
194
260
 
195
261
  {config.isLollipopChart && config.lollipopShape === 'circle' && (
196
- <circle cx={bar.y} cy={0 + lollipopBarWidth / 2} r={lollipopShapeSize / 2} fill={barColor} key={`circle--${bar.index}`} data-tooltip-html={tooltip} data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`} style={{ filter: 'unset', opacity: 1 }} />
262
+ <circle
263
+ display={displaylollipopShape}
264
+ cx={bar.y}
265
+ cy={0 + lollipopBarWidth / 2}
266
+ r={lollipopShapeSize / 2}
267
+ fill={barColor}
268
+ key={`circle--${bar.index}`}
269
+ data-tooltip-html={tooltip}
270
+ data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
271
+ style={{ filter: 'unset', opacity: 1 }}
272
+ />
197
273
  )}
198
274
  {config.isLollipopChart && config.lollipopShape === 'square' && (
199
275
  <rect
276
+ display={displaylollipopShape}
200
277
  x={bar.y > 10 ? bar.y - lollipopShapeSize / 2 : 0}
201
278
  y={0 - lollipopBarWidth / 2}
202
279
  width={lollipopShapeSize}
@@ -8,10 +8,12 @@ import { Text } from '@visx/text'
8
8
  // third party
9
9
  import chroma from 'chroma-js'
10
10
 
11
- const BarChartStackedHorizontal = props => {
11
+ import { type BarChartProps } from '../types/ChartProps'
12
+
13
+ const BarChartStackedHorizontal = (props: BarChartProps) => {
12
14
  const { xScale, yScale, xMax, yMax } = props
13
- const { transformedData: data, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, setSharedFilter, animatedChart, getTextWidth } = useContext(ConfigContext)
14
- const { isHorizontal, barBorderWidth, hasMultipleSeries, applyRadius, updateBars, isLabelBelowBar, displayNumbersOnBar, fontSize } = useBarChart()
15
+ const { transformedData: data, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, setSharedFilter, animatedChart, getTextWidth, setSeriesHighlight } = useContext(ConfigContext)
16
+ const { isHorizontal, barBorderWidth, hasMultipleSeries, applyRadius, updateBars, isLabelBelowBar, displayNumbersOnBar, fontSize, getAdditionalColumn, hoveredBar, onMouseLeaveBar, onMouseOverBar } = useBarChart()
15
17
  const { orientation, visualizationSubType } = config
16
18
 
17
19
  return (
@@ -31,18 +33,17 @@ const BarChartStackedHorizontal = props => {
31
33
  const yAxisValue = config.runtime.yAxis.type === 'date' ? formatDate(parseDate(data[bar.index][config.runtime.originalXAxis.dataKey])) : data[bar.index][config.runtime.originalXAxis.dataKey]
32
34
  const style = applyRadius(barStack.index)
33
35
  let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
34
- let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
35
36
  let textWidth = getTextWidth(xAxisValue, `normal ${fontSize[config.fontSize]}px sans-serif`)
36
- if (!hasMultipleSeries) {
37
- xAxisTooltip = config.isLegendValue ? `${bar.key}: ${xAxisValue}` : config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisTooltip
38
- }
39
- const tooltip = `<div>
40
- ${config.legend.showLegendValuesTooltip && config.runtime.seriesLabels && hasMultipleSeries ? `${config.runtime.seriesLabels[bar.key] || ''}<br/>` : ''}
41
- ${yAxisTooltip}<br />
42
- ${xAxisTooltip}
43
- </div>`
44
37
 
45
- if (chroma.contrast(labelColor, bar.color) < 4.9) {
38
+ const additionalColTooltip = getAdditionalColumn(hoveredBar)
39
+ const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${xAxisValue}`
40
+ const tooltip = `<ul>
41
+ <li class="tooltip-heading"">${yAxisTooltip}</li>
42
+ <li class="tooltip-body ">${tooltipBody}</li>
43
+ <li class="tooltip-body ">${additionalColTooltip}</li>
44
+ </li></ul>`
45
+
46
+ if (chroma.contrast(labelColor, colorScale(config.runtime.seriesLabels[bar.key])) < 4.9) {
46
47
  labelColor = '#FFFFFF'
47
48
  }
48
49
 
@@ -51,7 +52,7 @@ const BarChartStackedHorizontal = props => {
51
52
  <style>
52
53
  {`
53
54
  #barStack${barStack.index}-${bar.index} rect,
54
- #barStack${barStack.index}-${bar.index} foreignObject{
55
+ #barStack${barStack.index}-${bar.index} foreignObject div{
55
56
  animation-delay: ${barStack.index * 0.5}s;
56
57
  transform-origin: ${bar.x}px
57
58
  }
@@ -59,14 +60,16 @@ const BarChartStackedHorizontal = props => {
59
60
  </style>
60
61
  <Group key={index} id={`barStack${barStack.index}-${bar.index}`} className='stack horizontal'>
61
62
  <foreignObject
63
+ onMouseOver={() => onMouseOverBar(yAxisValue, bar.key)}
64
+ onMouseLeave={onMouseLeaveBar}
62
65
  key={`barstack-horizontal-${barStack.index}-${bar.index}-${index}`}
63
66
  className={`animated-chart group ${animatedChart ? 'animated' : ''}`}
64
67
  x={bar.x}
65
68
  y={bar.y}
69
+ style={{ transition: 'all 0.2s linear' }}
66
70
  width={bar.width}
67
71
  height={bar.height}
68
- style={{ background: bar.color, border: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px solid #333`, ...style }}
69
- opacity={transparentBar ? 0.5 : 1}
72
+ opacity={transparentBar ? 0.2 : 1}
70
73
  display={displayBar ? 'block' : 'none'}
71
74
  data-tooltip-html={tooltip}
72
75
  data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
@@ -77,7 +80,9 @@ const BarChartStackedHorizontal = props => {
77
80
  setSharedFilter(config.uid, bar)
78
81
  }
79
82
  }}
80
- ></foreignObject>
83
+ >
84
+ <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>
85
+ </foreignObject>
81
86
 
82
87
  {orientation === 'horizontal' && visualizationSubType === 'stacked' && isLabelBelowBar && barStack.index === 0 && !config.yAxis.hideLabel && (
83
88
  <Text
@@ -4,12 +4,14 @@ import { useBarChart } from '../hooks/useBarChart'
4
4
  import { BarStack } from '@visx/shape'
5
5
  import { Group } from '@visx/group'
6
6
  import { Text } from '@visx/text'
7
+ import { type BarChartProps } from '../types/ChartProps'
7
8
 
8
- const BarChartStackedVertical = props => {
9
+ const BarChartStackedVertical = (props: BarChartProps) => {
9
10
  const { xScale, yScale, xMax, yMax } = props
10
- const { transformedData: data, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, setSharedFilter } = useContext(ConfigContext)
11
- const { isHorizontal, barBorderWidth, hasMultipleSeries, applyRadius } = useBarChart()
11
+ const { transformedData, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, setSharedFilter } = useContext(ConfigContext)
12
+ const { isHorizontal, barBorderWidth, applyRadius, hoveredBar, getAdditionalColumn, onMouseLeaveBar, onMouseOverBar } = useBarChart()
12
13
  const { orientation } = config
14
+ const data = config.brush.active && config.brush.data?.length ? config.brush.data : transformedData
13
15
 
14
16
  return (
15
17
  config.visualizationSubType === 'stacked' &&
@@ -26,33 +28,23 @@ const BarChartStackedVertical = props => {
26
28
  // tooltips
27
29
  const xAxisValue = config.runtime.xAxis.type === 'date' ? formatDate(parseDate(data[bar.index][config.runtime.xAxis.dataKey])) : data[bar.index][config.runtime.xAxis.dataKey]
28
30
  const yAxisValue = formatNumber(bar.bar ? bar.bar.data[bar.key] : 0, 'left')
29
-
30
- if(!yAxisValue) return <></>
31
-
31
+ if (!yAxisValue) return
32
32
  const style = applyRadius(barStack.index)
33
- let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
34
33
  const xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
35
- if (!hasMultipleSeries) {
36
- yAxisTooltip = config.isLegendValue ? `${bar.key}: ${yAxisValue}` : config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
37
- }
38
-
39
- const {
40
- legend: { showLegendValuesTooltip },
41
- runtime: { seriesLabels }
42
- } = config
43
-
44
- const barStackTooltip = `<div>
45
- <p class="tooltip-heading"><strong>${xAxisTooltip}</strong></p>
46
- ${showLegendValuesTooltip && seriesLabels && hasMultipleSeries ? `${seriesLabels[bar.key] || ''}<br/>` : ''}
47
- ${yAxisTooltip}<br />
48
- </div>`
34
+ const additionalColTooltip = getAdditionalColumn(hoveredBar)
35
+ const tooltipBody = `${config.runtime.seriesLabels[bar.key]}: ${yAxisValue}`
36
+ const tooltip = `<ul>
37
+ <li class="tooltip-heading"">${xAxisTooltip}</li>
38
+ <li class="tooltip-body ">${tooltipBody}</li>
39
+ <li class="tooltip-body ">${additionalColTooltip}</li>
40
+ </li></ul>`
49
41
 
50
42
  return (
51
43
  <Group key={`${barStack.index}--${bar.index}--${orientation}`}>
52
44
  <style>
53
45
  {`
54
46
  #barStack${barStack.index}-${bar.index} rect,
55
- #barStack${barStack.index}-${bar.index} foreignObject{
47
+ #barStack${barStack.index}-${bar.index} foreignObject div{
56
48
  animation-delay: ${barStack.index * 0.5}s;
57
49
  transform-origin: ${barThicknessAdjusted / 2}px ${bar.y + bar.height}px
58
50
  }
@@ -63,15 +55,15 @@ const BarChartStackedVertical = props => {
63
55
  {yAxisValue}
64
56
  </Text>
65
57
  <foreignObject
58
+ onMouseOver={() => onMouseOverBar(xAxisValue, bar.key)}
59
+ onMouseLeave={onMouseLeaveBar}
66
60
  key={`bar-stack-${barStack.index}-${bar.index}`}
67
61
  x={barThickness * bar.index + offset}
68
62
  y={bar.y}
69
63
  width={barThicknessAdjusted}
70
64
  height={bar.height}
71
- style={{ background: bar.color, border: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px solid #333`, ...style }}
72
- opacity={transparentBar ? 0.5 : 1}
73
65
  display={displayBar ? 'block' : 'none'}
74
- data-tooltip-html={barStackTooltip}
66
+ data-tooltip-html={tooltip}
75
67
  data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
76
68
  onClick={e => {
77
69
  e.preventDefault()
@@ -80,7 +72,11 @@ const BarChartStackedVertical = props => {
80
72
  setSharedFilter(config.uid, bar)
81
73
  }
82
74
  }}
83
- ></foreignObject>
75
+ >
76
+ <div
77
+ style={{ transition: 'all 0.2s linear', opacity: transparentBar ? 0.2 : 1, width: barThicknessAdjusted, height: bar.height, background: colorScale(config.runtime.seriesLabels[bar.key]), border: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px solid #333`, ...style }}
78
+ ></div>
79
+ </foreignObject>
84
80
  </Group>
85
81
  </Group>
86
82
  )