@cdc/chart 4.23.7 → 4.23.8

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 (38) hide show
  1. package/LICENSE +201 -0
  2. package/dist/cdcchart.js +27964 -26942
  3. package/examples/feature/__data__/area-chart-date-apple.json +5122 -0
  4. package/examples/feature/__data__/city-temperature.json +2198 -0
  5. package/examples/feature/area/area-chart-category.json +45 -45
  6. package/examples/feature/area/area-chart-date-apple.json +10376 -0
  7. package/examples/feature/area/area-chart-date-city-temperature.json +4528 -0
  8. package/examples/feature/area/area-chart-date.json +111 -3
  9. package/examples/feature/forest-plot/broken.json +700 -0
  10. package/examples/feature/forest-plot/data.csv +24 -0
  11. package/examples/feature/forest-plot/forest-plot.json +717 -0
  12. package/examples/feature/pie/planet-pie-example-config.json +1 -1
  13. package/examples/private/confidence_interval_test.json +248 -0
  14. package/examples/private/tooltip-issue.json +45275 -0
  15. package/index.html +13 -11
  16. package/package.json +4 -3
  17. package/src/CdcChart.jsx +24 -14
  18. package/src/components/AreaChart.jsx +84 -59
  19. package/src/components/BarChart.Horizontal.jsx +251 -0
  20. package/src/components/BarChart.StackedHorizontal.jsx +118 -0
  21. package/src/components/BarChart.StackedVertical.jsx +93 -0
  22. package/src/components/BarChart.Vertical.jsx +204 -0
  23. package/src/components/BarChart.jsx +14 -674
  24. package/src/components/BarChartType.jsx +15 -0
  25. package/src/components/BrushHandle.jsx +17 -0
  26. package/src/components/DataTable.jsx +63 -21
  27. package/src/components/EditorPanel.jsx +351 -303
  28. package/src/components/ForestPlot.jsx +191 -0
  29. package/src/components/ForestPlotSettings.jsx +508 -0
  30. package/src/components/LineChart.jsx +2 -2
  31. package/src/components/LinearChart.jsx +115 -310
  32. package/src/data/initial-state.js +43 -0
  33. package/src/hooks/useBarChart.js +186 -0
  34. package/src/hooks/useEditorPermissions.js +218 -0
  35. package/src/hooks/useMinMax.js +15 -3
  36. package/src/hooks/useScales.js +45 -2
  37. package/src/hooks/useTooltip.jsx +407 -0
  38. package/src/scss/main.scss +7 -0
@@ -1,687 +1,27 @@
1
- import React, { useContext, useState, useEffect } from 'react'
1
+ import React, { useContext } from 'react'
2
+
3
+ // visx
2
4
  import { Group } from '@visx/group'
3
- import { BarGroup, BarStack, Bar } from '@visx/shape'
4
- import { Text } from '@visx/text'
5
- import chroma from 'chroma-js'
5
+ import { Bar } from '@visx/shape'
6
+
7
+ // cdc
8
+ import BarChartType from './BarChartType'
6
9
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
7
10
  import ConfigContext from '../ConfigContext'
8
- import { BarStackHorizontal } from '@visx/shape'
9
- import { useHighlightedBars } from '../hooks/useHighlightedBars'
10
-
11
- const BarChart = ({ xScale, yScale, seriesScale, xMax, yMax, getXAxisData, getYAxisData, animatedChart, visible, handleTooltipMouseOver, handleTooltipMouseOff, handleTooltipClick }) => {
12
- const { transformedData: data, colorScale, seriesHighlight, config, formatNumber, updateConfig, colorPalettes, tableData, formatDate, isNumber, getTextWidth, parseDate, setSharedFilter, setSharedFilterValue, dashboardConfig } = useContext(ConfigContext)
13
- const { HighLightedBarUtils } = useHighlightedBars(config)
14
- const { orientation, visualizationSubType } = config
15
- const isHorizontal = orientation === 'horizontal'
16
- const barBorderWidth = 1
17
- const lollipopBarWidth = config.lollipopSize === 'large' ? 7 : config.lollipopSize === 'medium' ? 6 : 5
18
- const lollipopShapeSize = config.lollipopSize === 'large' ? 14 : config.lollipopSize === 'medium' ? 12 : 10
19
-
20
- const isLabelBelowBar = config.yAxis.labelPlacement === 'Below Bar'
21
- const displayNumbersOnBar = config.yAxis.displayNumbersOnBar
22
- const section = config.orientation === 'horizontal' ? 'yAxis' : 'xAxis'
23
-
24
- const isRounded = config.barStyle === 'rounded'
25
- const isStacked = config.visualizationSubType === 'stacked'
26
- const tipRounding = config.tipRounding
27
- const radius = config.roundingStyle === 'standard' ? '8px' : config.roundingStyle === 'shallow' ? '5px' : config.roundingStyle === 'finger' ? '15px' : '0px'
28
- const stackCount = config.runtime.seriesKeys.length
29
- const fontSize = { small: 16, medium: 18, large: 20 }
30
- const hasMultipleSeries = Object.keys(config.runtime.seriesLabels).length > 1
31
-
32
- const applyRadius = index => {
33
- if (index === undefined || index === null || !isRounded) return {}
34
- let style = {}
35
-
36
- if ((isStacked && index + 1 === stackCount) || !isStacked) {
37
- style = isHorizontal ? { borderRadius: `0 ${radius} ${radius} 0` } : { borderRadius: `${radius} ${radius} 0 0` }
38
- }
39
- if (!isStacked && index === -1) {
40
- style = isHorizontal ? { borderRadius: `${radius} 0 0 ${radius} ` } : { borderRadius: ` 0 0 ${radius} ${radius}` }
41
- }
42
- if (tipRounding === 'full' && isStacked && index === 0 && stackCount > 1) {
43
- style = isHorizontal ? { borderRadius: `${radius} 0 0 ${radius}` } : { borderRadius: `0 0 ${radius} ${radius}` }
44
- }
45
- if (tipRounding === 'full' && ((isStacked && index === 0 && stackCount === 1) || !isStacked)) {
46
- style = { borderRadius: radius }
47
- }
48
- return style
49
- }
50
-
51
- const assignColorsToValues = () => {
52
- const palettesArr = colorPalettes[config.palette]
53
- const values = tableData.map(d => {
54
- return d[config.legend.colorCode]
55
- })
56
- // Map to hold unique values and their colors
57
- let colorMap = new Map()
58
- // Resultant array to hold colors to the values
59
- let result = []
60
-
61
- for (let i = 0; i < values.length; i++) {
62
- // If value not in map, add it and assign a color
63
- if (!colorMap.has(values[i])) {
64
- colorMap.set(values[i], palettesArr[colorMap.size % palettesArr.length])
65
- }
66
- // push the color to the result array
67
- result.push(colorMap.get(values[i]))
68
- }
69
- return result
70
- }
71
-
72
- const updateBars = defaultBars => {
73
- // function updates stacked && regular && lollipop horizontal bars
74
- if (config.visualizationType !== 'Bar' && !isHorizontal) return defaultBars
75
-
76
- const barsArr = [...defaultBars]
77
- let barHeight
78
-
79
- const heights = {
80
- stacked: config.barHeight,
81
- lollipop: lollipopBarWidth
82
- }
83
-
84
- if (!isStacked) {
85
- barHeight = heights[config.isLollipopChart ? 'lollipop' : 'stacked'] * stackCount
86
- } else {
87
- barHeight = heights.stacked
88
- }
89
-
90
- const labelHeight = isLabelBelowBar ? fontSize[config.fontSize] * 1.2 : 0
91
- let barSpace = Number(config.barSpace)
92
-
93
- // calculate height of container based height, space and fontSize of labels
94
- let totalHeight = barsArr.length * (barHeight + labelHeight + barSpace)
95
-
96
- if (isHorizontal) {
97
- config.heights.horizontal = totalHeight
98
- }
99
11
 
100
- // return new updated bars/groupes
101
- return barsArr.map((bar, i) => {
102
- // set bars Y dynamically to handle space between bars
103
- let y = 0
104
- bar.index !== 0 && (y = (barHeight + barSpace + labelHeight) * i)
105
-
106
- return { ...bar, y: y, height: barHeight }
107
- })
108
- }
109
-
110
- // Using State
111
- const [textWidth, setTextWidth] = useState(null)
112
-
113
- useEffect(() => {
114
- if (orientation === 'horizontal' && !config.yAxis.labelPlacement) {
115
- updateConfig({
116
- ...config,
117
- yAxis: {
118
- ...config,
119
- labelPlacement: 'Below Bar'
120
- }
121
- })
122
- }
123
- }, [config, updateConfig]) // eslint-disable-line
124
-
125
- useEffect(() => {
126
- if (config.isLollipopChart === false && config.barHeight < 25) {
127
- updateConfig({ ...config, barHeight: 25 })
128
- }
129
- }, [config.isLollipopChart]) // eslint-disable-line
130
-
131
- useEffect(() => {
132
- if (config.visualizationSubType === 'horizontal') {
133
- updateConfig({
134
- ...config,
135
- orientation: 'horizontal'
136
- })
137
- }
138
- }, []) // eslint-disable-line
139
-
140
- useEffect(() => {
141
- if (config.barStyle === 'lollipop' && !config.isLollipopChart) {
142
- updateConfig({ ...config, isLollipopChart: true })
143
- }
144
- if (isRounded || config.barStyle === 'flat') {
145
- updateConfig({ ...config, isLollipopChart: false })
146
- }
147
- }, [config.barStyle]) // eslint-disable-line
12
+ const BarChart = ({ xScale, yScale, seriesScale, xMax, yMax, handleTooltipMouseOver, handleTooltipMouseOff, handleTooltipClick }) => {
13
+ const { transformedData: data, config } = useContext(ConfigContext)
148
14
 
149
15
  return (
150
16
  <ErrorBoundary component='BarChart'>
151
17
  <Group left={parseFloat(config.runtime.yAxis.size)}>
152
- {/* Stacked Vertical */}
153
- {config.visualizationSubType === 'stacked' && !isHorizontal && (
154
- <BarStack data={data} keys={config.runtime.barSeriesKeys || config.runtime.seriesKeys} x={d => d[config.runtime.xAxis.dataKey]} xScale={xScale} yScale={yScale} color={colorScale}>
155
- {barStacks =>
156
- barStacks.reverse().map(barStack =>
157
- barStack.bars.map(bar => {
158
- let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
159
- let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
160
- let barThickness = xMax / barStack.bars.length
161
- let barThicknessAdjusted = barThickness * (config.barThickness || 0.8)
162
- let offset = (barThickness * (1 - (config.barThickness || 0.8))) / 2
163
- // tooltips
164
- const xAxisValue = config.runtime.xAxis.type === 'date' ? formatDate(parseDate(data[bar.index][config.runtime.xAxis.dataKey])) : data[bar.index][config.runtime.xAxis.dataKey]
165
- const yAxisValue = formatNumber(bar.bar ? bar.bar.data[bar.key] : 0, 'left')
166
-
167
- const style = applyRadius(barStack.index)
168
- let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
169
- const xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
170
- if (!hasMultipleSeries) {
171
- yAxisTooltip = config.isLegendValue ? `${bar.key}: ${yAxisValue}` : config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
172
- }
173
-
174
- const {
175
- legend: { showLegendValuesTooltip },
176
- runtime: { seriesLabels }
177
- } = config
178
-
179
- const barStackTooltip = `<div>
180
- <p class="tooltip-heading"><strong>${xAxisTooltip}</strong></p>
181
- ${showLegendValuesTooltip && seriesLabels && hasMultipleSeries ? `${seriesLabels[bar.key] || ''}<br/>` : ''}
182
- ${yAxisTooltip}<br />
183
- </div>`
184
-
185
- return (
186
- <Group key={`${barStack.index}--${bar.index}--${orientation}`}>
187
- <style>
188
- {`
189
- #barStack${barStack.index}-${bar.index} rect,
190
- #barStack${barStack.index}-${bar.index} foreignObject{
191
- animation-delay: ${barStack.index * 0.5}s;
192
- transform-origin: ${barThicknessAdjusted / 2}px ${bar.y + bar.height}px
193
- }
194
- `}
195
- </style>
196
- <Group key={`bar-stack-${barStack.index}-${bar.index}`} id={`barStack${barStack.index}-${bar.index}`} className='stack vertical'>
197
- <Text display={config.labels && displayBar ? 'block' : 'none'} opacity={transparentBar ? 0.5 : 1} x={barThickness * bar.index + offset} y={bar.y - 5} fill={'#000'} textAnchor='middle'>
198
- {yAxisValue}
199
- </Text>
200
- <foreignObject
201
- key={`bar-stack-${barStack.index}-${bar.index}`}
202
- x={barThickness * bar.index + offset}
203
- y={bar.y}
204
- width={barThicknessAdjusted}
205
- height={bar.height}
206
- style={{ background: bar.color, border: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px solid #333`, ...style }}
207
- opacity={transparentBar ? 0.5 : 1}
208
- display={displayBar ? 'block' : 'none'}
209
- data-tooltip-html={barStackTooltip}
210
- data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
211
- onClick={e => {
212
- e.preventDefault()
213
- if (setSharedFilter) {
214
- bar[config.xAxis.dataKey] = xAxisValue
215
- setSharedFilter(config.uid, bar)
216
- }
217
- }}
218
- ></foreignObject>
219
- </Group>
220
- </Group>
221
- )
222
- })
223
- )
224
- }
225
- </BarStack>
226
- )}
227
-
228
- {/* Stacked Horizontal */}
229
- {config.visualizationSubType === 'stacked' && isHorizontal && (
230
- <>
231
- <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'>
232
- {barStacks =>
233
- barStacks.map(barStack =>
234
- updateBars(barStack.bars).map((bar, index) => {
235
- let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
236
- let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
237
- config.barHeight = Number(config.barHeight)
238
- let labelColor = '#000000'
239
- // tooltips
240
- const xAxisValue = formatNumber(data[bar.index][bar.key], 'left')
241
- const yAxisValue = config.runtime.yAxis.type === 'date' ? formatDate(parseDate(data[bar.index][config.runtime.originalXAxis.dataKey])) : data[bar.index][config.runtime.originalXAxis.dataKey]
242
- const style = applyRadius(barStack.index)
243
- let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
244
- let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
245
- if (!hasMultipleSeries) {
246
- xAxisTooltip = config.isLegendValue ? `${bar.key}: ${xAxisValue}` : config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisTooltip
247
- }
248
- const tooltip = `<div>
249
- ${config.legend.showLegendValuesTooltip && config.runtime.seriesLabels && hasMultipleSeries ? `${config.runtime.seriesLabels[bar.key] || ''}<br/>` : ''}
250
- ${yAxisTooltip}<br />
251
- ${xAxisTooltip}
252
- </div>`
253
-
254
- if (chroma.contrast(labelColor, bar.color) < 4.9) {
255
- labelColor = '#FFFFFF'
256
- }
257
-
258
- return (
259
- <>
260
- <style>
261
- {`
262
- #barStack${barStack.index}-${bar.index} rect,
263
- #barStack${barStack.index}-${bar.index} foreignObject{
264
- animation-delay: ${barStack.index * 0.5}s;
265
- transform-origin: ${bar.x}px
266
- }
267
- `}
268
- </style>
269
- <Group key={index} id={`barStack${barStack.index}-${bar.index}`} className='stack horizontal'>
270
- <foreignObject
271
- key={`barstack-horizontal-${barStack.index}-${bar.index}-${index}`}
272
- className={`animated-chart group ${animatedChart ? 'animated' : ''}`}
273
- x={bar.x}
274
- y={bar.y}
275
- width={bar.width}
276
- height={bar.height}
277
- style={{ background: bar.color, border: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px solid #333`, ...style }}
278
- opacity={transparentBar ? 0.5 : 1}
279
- display={displayBar ? 'block' : 'none'}
280
- data-tooltip-html={tooltip}
281
- data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
282
- onClick={e => {
283
- e.preventDefault()
284
- if (setSharedFilter) {
285
- bar[config.xAxis.dataKey] = xAxisValue
286
- setSharedFilter(config.uid, bar)
287
- }
288
- }}
289
- ></foreignObject>
290
-
291
- {orientation === 'horizontal' && visualizationSubType === 'stacked' && isLabelBelowBar && barStack.index === 0 && !config.yAxis.hideLabel && (
292
- <Text
293
- x={`${bar.x + (config.isLollipopChart ? 15 : 5)}`} // padding
294
- y={bar.y + bar.height * 1.2}
295
- fill={'#000000'}
296
- textAnchor='start'
297
- verticalAnchor='start'
298
- >
299
- {yAxisValue}
300
- </Text>
301
- )}
302
-
303
- {displayNumbersOnBar && textWidth < bar.width && (
304
- <Text
305
- display={displayBar ? 'block' : 'none'}
306
- x={bar.x + barStack.bars[bar.index].width / 2} // padding
307
- y={bar.y + bar.height / 2}
308
- fill={labelColor}
309
- textAnchor='middle'
310
- verticalAnchor='middle'
311
- innerRef={e => {
312
- if (e) {
313
- // use font sizes and padding to set the bar height
314
- let elem = e.getBBox()
315
- setTextWidth(elem.width)
316
- }
317
- }}
318
- >
319
- {xAxisValue}
320
- </Text>
321
- )}
322
- </Group>
323
- </>
324
- )
325
- })
326
- )
327
- }
328
- </BarStackHorizontal>
329
- </>
330
- )}
331
-
332
- {/* Bar Groups: Not Stacked */}
333
- {config.visualizationSubType !== 'stacked' && (
334
- <Group>
335
- <BarGroup
336
- data={data}
337
- keys={config.runtime.barSeriesKeys || config.runtime.seriesKeys}
338
- height={yMax}
339
- x0={d => d[config.runtime.originalXAxis.dataKey]}
340
- x0Scale={config.runtime.horizontal ? yScale : xScale}
341
- x1Scale={seriesScale}
342
- yScale={config.runtime.horizontal ? xScale : yScale}
343
- color={() => {
344
- return ''
345
- }}
346
- >
347
- {barGroups => {
348
- return updateBars(barGroups).map((barGroup, index) => (
349
- <Group
350
- className={`bar-group-${barGroup.index}-${barGroup.x0}--${index} ${config.orientation}`}
351
- key={`bar-group-${barGroup.index}-${barGroup.x0}--${index}`}
352
- id={`bar-group-${barGroup.index}-${barGroup.x0}--${index}`}
353
- top={config.runtime.horizontal ? barGroup.y : 0}
354
- left={config.runtime.horizontal ? 0 : (xMax / barGroups.length) * barGroup.index}
355
- >
356
- {barGroup.bars.map((bar, index) => {
357
- const scaleVal = config.useLogScale ? 0.1 : 0
358
- const getHighlightedBarColorByValue = value => {
359
- const match = config?.highlightedBarValues.filter(item => {
360
- if (!item.value) return
361
- return config.xAxis.type === 'date' ? formatDate(parseDate(item.value)) === value : item.value === value
362
- })[0]
363
-
364
- if (!match?.color) return `rgba(255, 102, 1)`
365
- return match.color
366
- }
367
-
368
- const getHighlightedBarByValue = value => {
369
- const match = config?.highlightedBarValues.filter(item => {
370
- if (!item.value) return
371
- return config.xAxis.type === 'date' ? formatDate(parseDate(item.value)) === value : item.value === value
372
- })[0]
373
-
374
- if (!match?.color) return false
375
- return match
376
- }
377
-
378
- let highlightedBarValues = config.highlightedBarValues.map(item => item.value).filter(item => item !== ('' || undefined))
379
-
380
- highlightedBarValues = config.xAxis.type === 'date' ? HighLightedBarUtils.formatDates(highlightedBarValues) : highlightedBarValues
381
-
382
- let transparentBar = config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(bar.key) === -1
383
- let displayBar = config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(bar.key) !== -1
384
- let barHeight = orientation === 'horizontal' ? config.barHeight : isNumber(Math.abs(yScale(bar.value) - yScale(scaleVal))) ? Math.abs(yScale(bar.value) - yScale(scaleVal)) : 0
385
- let barY = bar.value >= 0 && isNumber(bar.value) ? bar.y : yScale(0)
386
- let barGroupWidth = ((config.runtime.horizontal ? yMax : xMax) / barGroups.length) * (config.barThickness || 0.8)
387
- let offset = (((config.runtime.horizontal ? yMax : xMax) / barGroups.length) * (1 - (config.barThickness || 0.8))) / 2
388
- const barX = bar.value < 0 ? Math.abs(xScale(bar.value)) : xScale(0)
389
- const barWidthHorizontal = Math.abs(xScale(bar.value) - xScale(scaleVal))
390
- // ! Unsure if this should go back.
391
- if (config.isLollipopChart) {
392
- offset = (config.runtime.horizontal ? yMax : xMax) / barGroups.length / 2 - lollipopBarWidth / 2
393
- }
394
- let palette = assignColorsToValues()
395
-
396
- let barWidth = config.isLollipopChart ? lollipopBarWidth : barGroupWidth / barGroup.bars.length
397
- let barColor = config.runtime.seriesLabels && config.runtime.seriesLabels[bar.key] ? colorScale(config.runtime.seriesLabels[bar.key]) : colorScale(bar.key)
398
- while (palette.length < barGroups.length) {
399
- palette = palette.concat(palette)
400
- }
401
- if (config.legend.colorCode && config.series.length === 1) barColor = palette[barGroup.index]
402
-
403
- let yAxisValue = formatNumber(bar.value, 'left')
404
- let xAxisValue = config.runtime[section].type === 'date' ? formatDate(parseDate(data[barGroup.index][config.runtime.originalXAxis.dataKey])) : data[barGroup.index][config.runtime.originalXAxis.dataKey]
405
-
406
- if (config.runtime.horizontal) {
407
- let tempValue = yAxisValue
408
- yAxisValue = xAxisValue
409
- xAxisValue = tempValue
410
- barWidth = config.barHeight
411
- }
412
-
413
- const barPosition = bar.value < 0 ? 'below' : 'above'
414
-
415
- // check if bar text/value string fits into each bars.
416
- let textWidth = getTextWidth(xAxisValue, `normal ${fontSize[config.fontSize]}px sans-serif`)
417
- let textFits = textWidth < barWidthHorizontal - 5 // minus padding 5
418
- let labelColor = '#000000'
419
-
420
- // Set label color
421
- if (barColor && labelColor) {
422
- if (chroma.contrast(labelColor, barColor) < 4.9) {
423
- labelColor = textFits ? '#FFFFFF' : '#000000'
424
- }
425
- }
426
-
427
- // Set if background is transparent'
428
- labelColor = HighLightedBarUtils.checkFontColor(yAxisValue, highlightedBarValues, labelColor)
429
-
430
- // control text position
431
- let textAnchor = textFits ? 'end' : 'start'
432
- let textAnchorLollipop = 'start'
433
- let textPadding = textFits ? -5 : 5
434
- let textPaddingLollipop = 10
435
- // if bars are negative we change positions of text
436
- if (barPosition === 'below') {
437
- textAnchor = textFits ? 'start' : 'end'
438
- textPadding = textFits ? 5 : -5
439
- if (config.isLollipopChart) {
440
- textAnchorLollipop = 'end'
441
- textPaddingLollipop = -10
442
- }
443
- }
444
-
445
- // create new Index based on bar value for border Radius
446
- const newIndex = bar.value < 0 ? -1 : index
447
- const style = applyRadius(newIndex)
448
-
449
- let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
450
- let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
451
- if (!hasMultipleSeries && config.runtime.horizontal) {
452
- 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
453
- }
454
- if (!hasMultipleSeries && !config.runtime.horizontal) {
455
- yAxisTooltip = config.isLegendValue ? `${bar.key}: ${yAxisValue}` : config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
456
- }
457
-
458
- const tooltip = `<ul>
459
- ${config.legend.showLegendValuesTooltip && config.runtime.seriesLabels && hasMultipleSeries ? `${config.runtime.seriesLabels[bar.key] || ''}<br/>` : ''}
460
- <li class="tooltip-heading">${yAxisTooltip}</li>
461
- <li class="tooltip-body">${xAxisTooltip}</li>
462
- </li></ul>`
463
-
464
- const isRegularLollipopColor = config.isLollipopChart && config.lollipopColorStyle === 'regular'
465
- const isTwoToneLollipopColor = config.isLollipopChart && config.lollipopColorStyle === 'two-tone'
466
- const isHighlightedBar = config.orientation === 'vertical' ? highlightedBarValues?.includes(xAxisValue) : highlightedBarValues?.includes(yAxisValue)
467
- const highlightedBarColor = config.orientation === 'vertical' ? getHighlightedBarColorByValue(xAxisValue) : getHighlightedBarColorByValue(yAxisValue)
468
- const highlightedBar = config.orientation === 'vertical' ? getHighlightedBarByValue(xAxisValue) : getHighlightedBarByValue(yAxisValue)
469
-
470
- const background = () => {
471
- if (isRegularLollipopColor) return barColor
472
- if (isTwoToneLollipopColor) return chroma(barColor).brighten(1)
473
- if (isHighlightedBar) return 'transparent'
474
- // loop through shared filters and get active values
475
- /* if (dashboardConfig && dashboardConfig?.dashboard.sharedFilters?.length > 0) {
476
- let activeFilters = []
477
- let backgroundColor = barColor
478
-
479
- const checkForResetValue = () => {
480
- return dashboardConfig.dashboard.sharedFilters?.map((filter, index) => {
481
- if (filter.resetLabel === filter.active) {
482
- backgroundColor = barColor
483
- } else {
484
- return backgroundColor
485
- }
486
- })
487
- }
488
-
489
- dashboardConfig.dashboard.sharedFilters?.forEach((filter, index) => {
490
- activeFilters.push(filter.active)
491
- })
492
-
493
- // if reset value is found use that.
494
-
495
- if (config.orientation === 'horizontal') {
496
- if (!activeFilters.includes(yAxisValue)) {
497
- backgroundColor = '#ccc'
498
- }
499
- }
500
-
501
- if (config.orientation !== 'horizontal') {
502
- if (!activeFilters.includes(xAxisValue)) {
503
- backgroundColor = '#ccc'
504
- }
505
- }
506
- checkForResetValue()
507
- return backgroundColor
508
- } */
509
- return barColor
510
- }
511
-
512
- const borderColor = isHighlightedBar ? highlightedBarColor : config.barHasBorder === 'true' ? '#000' : 'transparent'
513
-
514
- const borderWidth = isHighlightedBar ? highlightedBar.borderWidth : config.isLollipopChart ? 0 : config.barHasBorder === 'true' ? barBorderWidth : 0
515
-
516
- const finalStyle = {
517
- background: background(),
518
- borderColor,
519
- borderStyle: 'solid',
520
- borderWidth,
521
- ...style
522
- }
523
-
524
- return (
525
- <Group key={`${barGroup.index}--${index}--${orientation}`}>
526
- {/* This feels gross but inline transition was not working well*/}
527
- <style>
528
- {`
529
- .linear #barGroup${barGroup.index},
530
- .Combo #barGroup${barGroup.index} {
531
- transform-origin: 0 ${barY + barHeight}px;
532
- }
533
- `}
534
- </style>
535
- <Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
536
- <foreignObject
537
- id={`barGroup${barGroup.index}`}
538
- key={`bar-group-bar-${barGroup.index}-${bar.index}-${bar.value}-${bar.key}`}
539
- x={config.runtime.horizontal ? barX : barWidth * bar.index + offset}
540
- y={config.runtime.horizontal ? barWidth * bar.index : barY}
541
- width={config.runtime.horizontal ? barWidthHorizontal : barWidth}
542
- height={isHorizontal && !config.isLollipopChart ? barWidth : isHorizontal && config.isLollipopChart ? lollipopBarWidth : barHeight}
543
- style={finalStyle}
544
- opacity={transparentBar ? 0.5 : 1}
545
- display={displayBar ? 'block' : 'none'}
546
- data-tooltip-html={tooltip}
547
- data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
548
- onClick={e => {
549
- e.preventDefault()
550
- if (setSharedFilter) {
551
- bar[config.xAxis.dataKey] = config.orientation === 'horizontal' ? yAxisValue : xAxisValue
552
- setSharedFilter(config.uid, bar)
553
- }
554
- }}
555
- ></foreignObject>
556
- {orientation === 'horizontal' && !config.isLollipopChart && displayNumbersOnBar && (
557
- <Text // prettier-ignore
558
- display={displayBar ? 'block' : 'none'}
559
- x={bar.y}
560
- y={config.barHeight / 2 + config.barHeight * bar.index}
561
- fill={labelColor}
562
- dx={textPadding}
563
- verticalAnchor='middle'
564
- textAnchor={textAnchor}
565
- >
566
- {xAxisValue}
567
- </Text>
568
- )}
569
- {orientation === 'horizontal' && config.isLollipopChart && displayNumbersOnBar && (
570
- <Text
571
- display={displayBar ? 'block' : 'none'}
572
- x={bar.y} // padding
573
- y={0}
574
- fill={'#000000'}
575
- dx={textPaddingLollipop}
576
- textAnchor={textAnchorLollipop}
577
- verticalAnchor='middle'
578
- fontWeight={'normal'}
579
- >
580
- {xAxisValue}
581
- </Text>
582
- )}
583
- {orientation === 'horizontal' && isLabelBelowBar && !config.yAxis.hideLabel && (
584
- <Text x={config.yAxis.hideAxis ? 0 : 5} y={barGroup.height} dy={4} verticalAnchor={'start'} textAnchor={'start'}>
585
- {config.runtime.yAxis.type === 'date'
586
- ? formatDate(parseDate(data[barGroup.index][config.runtime.originalXAxis.dataKey]))
587
- : isHorizontal
588
- ? data[barGroup.index][config.runtime.originalXAxis.dataKey]
589
- : formatNumber(data[barGroup.index][config.runtime.originalXAxis.dataKey])}
590
- </Text>
591
- )}
592
-
593
- {orientation === 'vertical' && (
594
- <Text display={config.labels && displayBar ? 'block' : 'none'} opacity={transparentBar ? 0.5 : 1} x={barWidth * (bar.index + 0.5) + offset} y={barY - 5} fill={labelColor} textAnchor='middle'>
595
- {yAxisValue}
596
- </Text>
597
- )}
598
- {config.isLollipopChart && config.lollipopShape === 'circle' && (
599
- <circle
600
- cx={orientation === 'horizontal' ? bar.y : barWidth * (barGroup.bars.length - bar.index - 1) + (isLabelBelowBar && orientation === 'horizontal' ? 0 : offset) + lollipopShapeSize / 3.5}
601
- cy={orientation === 'horizontal' ? 0 + lollipopBarWidth / 2 : bar.y}
602
- r={lollipopShapeSize / 2}
603
- fill={barColor}
604
- key={`circle--${bar.index}`}
605
- data-tooltip-html={tooltip}
606
- data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
607
- style={{ filter: 'unset', opacity: 1 }}
608
- />
609
- )}
610
- {config.isLollipopChart && config.lollipopShape === 'square' && (
611
- <rect
612
- x={orientation === 'horizontal' && bar.y > 10 ? bar.y - lollipopShapeSize / 2 : orientation === 'horizontal' && bar.y < 10 ? 0 : orientation !== 'horizontal' ? offset - lollipopBarWidth / 2 : barWidth * (barGroup.bars.length - bar.index - 1) + offset - 5.25}
613
- y={orientation === 'horizontal' ? 0 - lollipopBarWidth / 2 : barY}
614
- width={lollipopShapeSize}
615
- height={lollipopShapeSize}
616
- fill={barColor}
617
- key={`circle--${bar.index}`}
618
- data-tooltip-html={tooltip}
619
- data-tooltip-id={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
620
- style={{ opacity: 1, filter: 'unset' }}
621
- >
622
- <animate attributeName='height' values={`0, ${lollipopShapeSize}`} dur='2.5s' />
623
- </rect>
624
- )}
625
- </Group>
626
- </Group>
627
- )
628
- })}
629
- </Group>
630
- ))
631
- }}
632
- </BarGroup>
633
-
634
- {Object.keys(config.confidenceKeys).length > 0
635
- ? data.map(d => {
636
- let xPos, yPos
637
- let upperPos
638
- let lowerPos
639
- let tickWidth = 5
640
- // DEV-3264 Make Confidence Intervals work on horizontal bar charts
641
- if (orientation === 'horizontal') {
642
- yPos = yScale(getXAxisData(d)) - 0.75 * config.barHeight
643
- upperPos = xScale(getYAxisData(d, config.confidenceKeys.upper))
644
- lowerPos = xScale(getYAxisData(d, config.confidenceKeys.lower))
645
- return (
646
- <path
647
- key={`confidence-interval-h-${yPos}-${d[config.runtime.originalXAxis.dataKey]}`}
648
- stroke='#333'
649
- strokeWidth='px'
650
- d={`
651
- M${lowerPos} ${yPos - tickWidth}
652
- L${lowerPos} ${yPos + tickWidth}
653
- M${lowerPos} ${yPos}
654
- L${upperPos} ${yPos}
655
- M${upperPos} ${yPos - tickWidth}
656
- L${upperPos} ${yPos + tickWidth} `}
657
- />
658
- )
659
- } else {
660
- xPos = xScale(getXAxisData(d))
661
- upperPos = yScale(getYAxisData(d, config.confidenceKeys.lower))
662
- lowerPos = yScale(getYAxisData(d, config.confidenceKeys.upper))
663
- return (
664
- <path
665
- key={`confidence-interval-v-${yPos}-${d[config.runtime.originalXAxis.dataKey]}`}
666
- stroke='#333'
667
- strokeWidth='px'
668
- d={`
669
- M${xPos - tickWidth} ${upperPos}
670
- L${xPos + tickWidth} ${upperPos}
671
- M${xPos} ${upperPos}
672
- L${xPos} ${lowerPos}
673
- M${xPos - tickWidth} ${lowerPos}
674
- L${xPos + tickWidth} ${lowerPos}`}
675
- />
676
- )
677
- }
678
- })
679
- : ''}
680
- </Group>
681
- )}
18
+ <BarChartType.StackedVertical xScale={xScale} yScale={yScale} xMax={xMax} yMax={yMax} />
19
+ <BarChartType.StackedHorizontal xScale={xScale} yScale={yScale} xMax={xMax} yMax={yMax} />
20
+ <BarChartType.Vertical xScale={xScale} yScale={yScale} xMax={xMax} yMax={yMax} seriesScale={seriesScale} />
21
+ <BarChartType.Horizontal xScale={xScale} yScale={yScale} xMax={xMax} yMax={yMax} seriesScale={seriesScale} />
682
22
 
683
23
  {/* tooltips */}
684
- {orientation !== 'horizontal' && <Bar key={'bars'} width={Number(xMax)} height={Number(yMax)} fill={false ? 'red' : 'transparent'} fillOpacity={0.05} onMouseMove={e => handleTooltipMouseOver(e, data)} onMouseOut={handleTooltipMouseOff} onClick={e => handleTooltipClick(e, data)} />}
24
+ <Bar key={'bars'} width={Number(xMax)} height={Number(yMax)} fill={false ? 'red' : 'transparent'} fillOpacity={0.05} onMouseMove={e => handleTooltipMouseOver(e, data)} onMouseOut={handleTooltipMouseOff} onClick={e => handleTooltipClick(e, data)} />
685
25
  </Group>
686
26
  </ErrorBoundary>
687
27
  )