@cdc/chart 4.23.5 → 4.23.7

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.
@@ -1,6 +1,6 @@
1
1
  import React, { useContext, useState, useEffect } from 'react'
2
2
  import { Group } from '@visx/group'
3
- import { BarGroup, BarStack } from '@visx/shape'
3
+ import { BarGroup, BarStack, Bar } from '@visx/shape'
4
4
  import { Text } from '@visx/text'
5
5
  import chroma from 'chroma-js'
6
6
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
@@ -8,8 +8,8 @@ import ConfigContext from '../ConfigContext'
8
8
  import { BarStackHorizontal } from '@visx/shape'
9
9
  import { useHighlightedBars } from '../hooks/useHighlightedBars'
10
10
 
11
- export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getXAxisData, getYAxisData, animatedChart, visible }) {
12
- const { transformedData: data, colorScale, seriesHighlight, config, formatNumber, updateConfig, colorPalettes, tableData, formatDate, isNumber, getTextWidth, parseDate } = useContext(ConfigContext)
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
13
  const { HighLightedBarUtils } = useHighlightedBars(config)
14
14
  const { orientation, visualizationSubType } = config
15
15
  const isHorizontal = orientation === 'horizontal'
@@ -63,7 +63,7 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
63
63
  if (!colorMap.has(values[i])) {
64
64
  colorMap.set(values[i], palettesArr[colorMap.size % palettesArr.length])
65
65
  }
66
- // push the colosr to the result array
66
+ // push the color to the result array
67
67
  result.push(colorMap.get(values[i]))
68
68
  }
69
69
  return result
@@ -171,11 +171,17 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
171
171
  yAxisTooltip = config.isLegendValue ? `${bar.key}: ${yAxisValue}` : config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
172
172
  }
173
173
 
174
- const tooltip = `<div>
175
- ${config.legend.showLegendValuesTooltip && config.runtime.seriesLabels && hasMultipleSeries ? `${config.runtime.seriesLabels[bar.key] || ''}<br/>` : ''}
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/>` : ''}
176
182
  ${yAxisTooltip}<br />
177
- ${xAxisTooltip}
178
183
  </div>`
184
+
179
185
  return (
180
186
  <Group key={`${barStack.index}--${bar.index}--${orientation}`}>
181
187
  <style>
@@ -200,8 +206,15 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
200
206
  style={{ background: bar.color, border: `${config.barHasBorder === 'true' ? barBorderWidth : 0}px solid #333`, ...style }}
201
207
  opacity={transparentBar ? 0.5 : 1}
202
208
  display={displayBar ? 'block' : 'none'}
203
- data-tooltip-html={tooltip}
209
+ data-tooltip-html={barStackTooltip}
204
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
+ }}
205
218
  ></foreignObject>
206
219
  </Group>
207
220
  </Group>
@@ -266,6 +279,13 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
266
279
  display={displayBar ? 'block' : 'none'}
267
280
  data-tooltip-html={tooltip}
268
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
+ }}
269
289
  ></foreignObject>
270
290
 
271
291
  {orientation === 'horizontal' && visualizationSubType === 'stacked' && isLabelBelowBar && barStack.index === 0 && !config.yAxis.hideLabel && (
@@ -429,17 +449,17 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
429
449
  let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
430
450
  let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
431
451
  if (!hasMultipleSeries && config.runtime.horizontal) {
432
- xAxisTooltip = config.isLegendValue ? `${bar.key}: ${xAxisValue}` : config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
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
433
453
  }
434
454
  if (!hasMultipleSeries && !config.runtime.horizontal) {
435
455
  yAxisTooltip = config.isLegendValue ? `${bar.key}: ${yAxisValue}` : config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
436
456
  }
437
457
 
438
- const tooltip = `<div>
458
+ const tooltip = `<ul>
439
459
  ${config.legend.showLegendValuesTooltip && config.runtime.seriesLabels && hasMultipleSeries ? `${config.runtime.seriesLabels[bar.key] || ''}<br/>` : ''}
440
- ${yAxisTooltip}<br />
441
- ${xAxisTooltip}
442
- </div>`
460
+ <li class="tooltip-heading">${yAxisTooltip}</li>
461
+ <li class="tooltip-body">${xAxisTooltip}</li>
462
+ </li></ul>`
443
463
 
444
464
  const isRegularLollipopColor = config.isLollipopChart && config.lollipopColorStyle === 'regular'
445
465
  const isTwoToneLollipopColor = config.isLollipopChart && config.lollipopColorStyle === 'two-tone'
@@ -447,14 +467,54 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
447
467
  const highlightedBarColor = config.orientation === 'vertical' ? getHighlightedBarColorByValue(xAxisValue) : getHighlightedBarColorByValue(yAxisValue)
448
468
  const highlightedBar = config.orientation === 'vertical' ? getHighlightedBarByValue(xAxisValue) : getHighlightedBarByValue(yAxisValue)
449
469
 
450
- const background = isRegularLollipopColor ? barColor : isTwoToneLollipopColor ? chroma(barColor).brighten(1) : isHighlightedBar ? 'transparent' : barColor
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
+ }
451
511
 
452
512
  const borderColor = isHighlightedBar ? highlightedBarColor : config.barHasBorder === 'true' ? '#000' : 'transparent'
453
513
 
454
514
  const borderWidth = isHighlightedBar ? highlightedBar.borderWidth : config.isLollipopChart ? 0 : config.barHasBorder === 'true' ? barBorderWidth : 0
455
515
 
456
516
  const finalStyle = {
457
- background,
517
+ background: background(),
458
518
  borderColor,
459
519
  borderStyle: 'solid',
460
520
  borderWidth,
@@ -485,6 +545,13 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
485
545
  display={displayBar ? 'block' : 'none'}
486
546
  data-tooltip-html={tooltip}
487
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
+ }}
488
555
  ></foreignObject>
489
556
  {orientation === 'horizontal' && !config.isLollipopChart && displayNumbersOnBar && (
490
557
  <Text // prettier-ignore
@@ -612,7 +679,12 @@ export default function BarChart({ xScale, yScale, seriesScale, xMax, yMax, getX
612
679
  : ''}
613
680
  </Group>
614
681
  )}
682
+
683
+ {/* 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)} />}
615
685
  </Group>
616
686
  </ErrorBoundary>
617
687
  )
618
688
  }
689
+
690
+ export default BarChart
@@ -2,6 +2,7 @@ import React, { useContext, useEffect, useState, useMemo } from 'react'
2
2
  import { useTable, useSortBy, useResizeColumns, useBlockLayout } from 'react-table'
3
3
  import Papa from 'papaparse'
4
4
  import { Base64 } from 'js-base64'
5
+ import { colorPalettesChart } from '@cdc/core/data/colorPalettes'
5
6
 
6
7
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
7
8
  import LegendCircle from '@cdc/core/components/LegendCircle'
@@ -9,14 +10,15 @@ import Icon from '@cdc/core/components/ui/Icon'
9
10
 
10
11
  import ConfigContext from '../ConfigContext'
11
12
 
12
- import CoveMediaControls from '@cdc/core/components/CoveMediaControls'
13
+ import MediaControls from '@cdc/core/components/MediaControls'
13
14
 
14
15
  export default function DataTable() {
15
- const { rawData, tableData: data, config, colorScale, parseDate, formatDate, formatNumber: numberFormatter, colorPalettes } = useContext(ConfigContext)
16
+ const { rawData, tableData: data, config, colorScale, parseDate, formatDate, formatNumber: numberFormatter, colorPalettes, currentViewport } = useContext(ConfigContext)
16
17
 
17
18
  const section = config.orientation === 'horizontal' ? 'yAxis' : 'xAxis'
18
19
  const [tableExpanded, setTableExpanded] = useState(config.table.expanded)
19
20
  const [accessibilityLabel, setAccessibilityLabel] = useState('')
21
+ const isLegendBottom = ['sm', 'xs', 'xxs'].includes(currentViewport)
20
22
 
21
23
  const DownloadButton = ({ data }, type) => {
22
24
  const fileName = `${config.title.substring(0, 50)}.csv`
@@ -93,24 +95,29 @@ export default function DataTable() {
93
95
  {
94
96
  Header: '',
95
97
  Cell: ({ row }) => {
96
- const seriesLabel = config.runtime.seriesLabels ? config.runtime.seriesLabels[row.original] : row.original
98
+ const getSeriesLabel = () => {
99
+ let userUpdatedSeriesName = config.series.filter(series => series.dataKey === row.original)?.[0]?.name
100
+
101
+ if (userUpdatedSeriesName) return userUpdatedSeriesName
102
+ if (config.runtimeSeriesLabels) return config.runtime.seriesLabels[row.original]
103
+ return row.original
104
+ }
97
105
  return (
98
106
  <>
99
107
  {config.visualizationType !== 'Pie' && (
100
108
  <LegendCircle
101
109
  fill={
102
- // non-dynamic leged
103
- !config.legend.dynamicLegend
104
- ? colorScale(seriesLabel)
105
- : // dynamic legend
106
- config.legend.dynamicLegend
110
+ // non-dynamic legend
111
+ !config.legend.dynamicLegend && config.visualizationType !== 'Forecasting'
112
+ ? colorScale(getSeriesLabel())
113
+ : config.legend.dynamicLegend
107
114
  ? colorPalettes[config.palette][row.index]
108
115
  : // fallback
109
116
  '#000'
110
117
  }
111
118
  />
112
119
  )}
113
- <span>{seriesLabel}</span>
120
+ <span>{getSeriesLabel()}</span>
114
121
  </>
115
122
  )
116
123
  },
@@ -127,7 +134,21 @@ export default function DataTable() {
127
134
  const newCol = {
128
135
  Header: resolveTableHeader(),
129
136
  Cell: ({ row }) => {
130
- return <>{numberFormatter(d[row.original], 'left')}</>
137
+ let leftAxisItems = config.series.filter(item => item?.axis === 'Left')
138
+ let rightAxisItems = config.series.filter(item => item?.axis === 'Right')
139
+ let resolvedAxis = ''
140
+
141
+ leftAxisItems.map(leftSeriesItem => {
142
+ if (leftSeriesItem.dataKey === row.original) resolvedAxis = 'left'
143
+ })
144
+
145
+ rightAxisItems.map(rightSeriesItem => {
146
+ if (rightSeriesItem.dataKey === row.original) resolvedAxis = 'right'
147
+ })
148
+
149
+ if (config.visualizationType !== 'Combo') resolvedAxis = 'left'
150
+
151
+ return <>{numberFormatter(d[row.original], resolvedAxis)}</>
131
152
  },
132
153
  id: `${d[config.runtime.originalXAxis.dataKey]}--${index}`,
133
154
  canSort: true
@@ -210,12 +231,12 @@ export default function DataTable() {
210
231
 
211
232
  return (
212
233
  <ErrorBoundary component='DataTable'>
213
- <CoveMediaControls.Section classes={['download-links']}>
214
- <CoveMediaControls.Link config={config} />
234
+ <MediaControls.Section classes={['download-links']}>
235
+ <MediaControls.Link config={config} />
215
236
  {config.table.download && <DownloadButton data={rawData} type='link' />}
216
- </CoveMediaControls.Section>
237
+ </MediaControls.Section>
217
238
 
218
- <section id={config?.title ? `dataTableSection__${config?.title.replace(/\s/g, '')}` : `dataTableSection`} className={`data-table-container`} aria-label={accessibilityLabel}>
239
+ <section style={{ marginTop: !isLegendBottom ? config.dynamicMarginTop + 'px' : '0px' }} id={config?.title ? `dataTableSection__${config?.title.replace(/\s/g, '')}` : `dataTableSection`} className={`data-table-container`} aria-label={accessibilityLabel}>
219
240
  <div
220
241
  role='button'
221
242
  className={tableExpanded ? 'data-table-heading' : 'collapsed data-table-heading'}