@cdc/chart 4.25.7 → 4.25.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/chart",
3
- "version": "4.25.7",
3
+ "version": "4.25.8",
4
4
  "description": "React component for visualizing tabular data in various types of charts",
5
5
  "moduleName": "CdcChart",
6
6
  "main": "dist/cdcchart",
@@ -26,7 +26,7 @@
26
26
  },
27
27
  "license": "Apache-2.0",
28
28
  "dependencies": {
29
- "@cdc/core": "^4.25.7",
29
+ "@cdc/core": "^4.25.8",
30
30
  "@hello-pangea/dnd": "^16.2.0",
31
31
  "@react-spring/web": "^9.7.5",
32
32
  "@visx/axis": "3.12.0",
@@ -54,7 +54,7 @@
54
54
  "react": "^18.2.0",
55
55
  "react-dom": "^18.2.0"
56
56
  },
57
- "gitHead": "9062881d50c824ee6cdd71868bafd016a5e5694d",
57
+ "gitHead": "e369994230b5e3facff224e1d89d5937528ac5a0",
58
58
  "devDependencies": {
59
59
  "@types/d3-array": "^3.2.1",
60
60
  "@types/d3-format": "^3.0.4",
package/src/CdcChart.tsx CHANGED
@@ -14,9 +14,16 @@ interface CdcChartProps {
14
14
  isEditor?: boolean
15
15
  isDebug?: boolean
16
16
  config?: ChartConfig
17
+ interactionLabel?: string
17
18
  }
18
19
 
19
- const CdcChartWrapper: React.FC<CdcChartProps> = ({ configUrl, isEditor, isDebug, config: editorsConfig }) => {
20
+ const CdcChartWrapper: React.FC<CdcChartProps> = ({
21
+ configUrl,
22
+ isEditor,
23
+ isDebug,
24
+ config: editorsConfig,
25
+ interactionLabel = ''
26
+ }) => {
20
27
  const editorContext = useContext(EditorContext)
21
28
  const [config, _setConfig] = useState<ChartConfig>({} as ChartConfig)
22
29
  const setConfig = newConfig => {
@@ -89,7 +96,7 @@ const CdcChartWrapper: React.FC<CdcChartProps> = ({ configUrl, isEditor, isDebug
89
96
 
90
97
  if (isLoading) return <Loading />
91
98
 
92
- return <CdcChart config={config} isEditor={isEditor} isDebug={isDebug} />
99
+ return <CdcChart config={config} isEditor={isEditor} isDebug={isDebug} interactionLabel={interactionLabel} />
93
100
  }
94
101
 
95
102
  export default CdcChartWrapper
@@ -82,6 +82,7 @@ import { VizFilter } from '@cdc/core/types/VizFilter'
82
82
  import { getNewRuntime } from './helpers/getNewRuntime'
83
83
  import FootnotesStandAlone from '@cdc/core/components/Footnotes/FootnotesStandAlone'
84
84
  import { Datasets } from '@cdc/core/types/DataSet'
85
+ import { publishAnalyticsEvent } from '@cdc/core/helpers/metrics/helpers'
85
86
 
86
87
  interface CdcChartProps {
87
88
  config?: ChartConfig
@@ -96,6 +97,7 @@ interface CdcChartProps {
96
97
  setSharedFilterValue?: (value: any) => void
97
98
  dashboardConfig?: DashboardConfig
98
99
  datasets?: Datasets
100
+ interactionLabel: string
99
101
  }
100
102
  const CdcChart: React.FC<CdcChartProps> = ({
101
103
  config: configObj,
@@ -108,7 +110,8 @@ const CdcChart: React.FC<CdcChartProps> = ({
108
110
  setSharedFilter,
109
111
  setSharedFilterValue,
110
112
  dashboardConfig,
111
- datasets
113
+ datasets,
114
+ interactionLabel
112
115
  }) => {
113
116
  const transform = new DataTransform()
114
117
  const initialState = getInitialState(configObj)
@@ -465,6 +468,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
465
468
  if (container && !isLoading && !_.isEmpty(config) && !coveLoadedEventRan) {
466
469
  publish('cove_loaded', { config: config })
467
470
  dispatch({ type: 'SET_LOADED_EVENT', payload: true })
471
+ publishAnalyticsEvent('chart_loaded', 'load', interactionLabel, 'chart')
468
472
  }
469
473
  }, [container, config, isLoading]) // eslint-disable-line
470
474
 
@@ -554,6 +558,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
554
558
  } catch (e) {
555
559
  console.error('COVE:', e.message)
556
560
  }
561
+ publishAnalyticsEvent('chart_legend_reset', 'click', interactionLabel, 'chart')
557
562
  dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: [] })
558
563
  }
559
564
 
@@ -907,6 +912,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
907
912
  setFilters={setFilters}
908
913
  excludedData={excludedData}
909
914
  dimensions={dimensions}
915
+ interactionLabel={interactionLabel}
910
916
  />
911
917
  )}
912
918
  <SkipTo skipId={handleChartTabbing(config, legendId)} skipMessage='Skip Over Chart Container' />
@@ -985,6 +991,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
985
991
  setFilters={setFilters}
986
992
  excludedData={excludedData}
987
993
  dimensions={dimensions}
994
+ interactionLabel={interactionLabel}
988
995
  />
989
996
  {config?.introText && (
990
997
  <section className='introText mb-4' style={{ padding: '0px 0 35px' }}>
@@ -1012,7 +1019,11 @@ const CdcChart: React.FC<CdcChartProps> = ({
1012
1019
  {!config.legend.hide &&
1013
1020
  config.visualizationType !== 'Spark Line' &&
1014
1021
  config.visualizationType !== 'Sankey' && (
1015
- <Legend ref={legendRef} skipId={handleChartTabbing(config, legendId)} />
1022
+ <Legend
1023
+ ref={legendRef}
1024
+ skipId={handleChartTabbing(config, legendId)}
1025
+ interactionLabel={interactionLabel}
1026
+ />
1016
1027
  )}
1017
1028
  </LegendWrapper>
1018
1029
  {/* Link */}
@@ -1034,6 +1045,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1034
1045
  type='image'
1035
1046
  state={config}
1036
1047
  elementToCapture={imageId}
1048
+ interactionLabel={interactionLabel}
1037
1049
  />
1038
1050
  )}
1039
1051
  {config.table.showDownloadPdfButton && (
@@ -1043,6 +1055,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1043
1055
  type='pdf'
1044
1056
  state={config}
1045
1057
  elementToCapture={imageId}
1058
+ interactionLabel={interactionLabel}
1046
1059
  />
1047
1060
  )}
1048
1061
  </MediaControls.Section>
@@ -1054,7 +1067,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1054
1067
  (config.visualizationType === 'Sankey' && config.table.show)) && (
1055
1068
  <DataTable
1056
1069
  /* changing the "key" will force the table to re-render
1057
- when the default sort changes while editing */
1070
+ when the default sort changes while editing */
1058
1071
  key={dataTableDefaultSortBy}
1059
1072
  config={pivotDynamicSeries(config)}
1060
1073
  rawData={
@@ -1076,6 +1089,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
1076
1089
  viewport={currentViewport}
1077
1090
  tabbingId={handleChartTabbing(config, legendId)}
1078
1091
  colorScale={colorScale}
1092
+ interactionLabel={interactionLabel}
1079
1093
  />
1080
1094
  )}
1081
1095
  {config?.annotations?.length > 0 && <Annotation.Dropdown />}
@@ -115,9 +115,15 @@ export const BarChartHorizontal = () => {
115
115
  numbericBarHeight = 25
116
116
  }
117
117
  let barY = bar.value >= 0 && isNumber(bar.value) ? bar.y : yScale(scaleVal)
118
- const defaultBarWidth = Math.abs(xScale(bar.value) - xScale(scaleVal))
118
+ let defaultBarWidth = Math.abs(xScale(bar.value) - xScale(scaleVal))
119
119
  const isPositiveBar = bar.value >= 0 && isNumber(bar.value)
120
120
 
121
+ const MINIMUM_BAR_HEIGHT = 3
122
+ if (isPositiveBar && barGroup.bars.length === 1 && defaultBarWidth < MINIMUM_BAR_HEIGHT) {
123
+ defaultBarWidth = MINIMUM_BAR_HEIGHT
124
+ barY = yScale(0) - MINIMUM_BAR_HEIGHT
125
+ }
126
+
121
127
  const barX = bar.value < 0 ? Math.abs(xScale(bar.value)) : xScale(scaleVal)
122
128
  const yAxisValue = formatNumber(bar.value, 'left')
123
129
  const xAxisValue =
@@ -166,7 +172,7 @@ export const BarChartHorizontal = () => {
166
172
  </li></ul>`
167
173
 
168
174
  // configure colors
169
- let labelColor = '#000000'
175
+ let labelColor = APP_FONT_COLOR
170
176
  labelColor = HighLightedBarUtils.checkFontColor(yAxisValue, highlightedBarValues, labelColor) // Set if background is transparent'
171
177
  let barColor =
172
178
  config.runtime.seriesLabels && config.runtime.seriesLabels[bar.key]
@@ -184,7 +190,7 @@ export const BarChartHorizontal = () => {
184
190
  const borderColor = isHighlightedBar
185
191
  ? highlightedBarColor
186
192
  : config.barHasBorder === 'true'
187
- ? '#000'
193
+ ? APP_FONT_COLOR
188
194
  : 'transparent'
189
195
  const borderWidth = isHighlightedBar
190
196
  ? highlightedBar.borderWidth
@@ -298,7 +304,7 @@ export const BarChartHorizontal = () => {
298
304
  : pd.symbol === 'Double Asterisk'
299
305
  ? barHeight
300
306
  : barHeight / 1.5
301
- const fillColor = pd.displayGray ? '#8b8b8a' : '#000'
307
+ const fillColor = pd.displayGray ? '#8b8b8a' : APP_FONT_COLOR
302
308
  return (
303
309
  <Text // prettier-ignore
304
310
  key={index}
@@ -366,7 +372,7 @@ export const BarChartHorizontal = () => {
366
372
  display={displayBar ? 'block' : 'none'}
367
373
  x={bar.y}
368
374
  y={0}
369
- fill={'#000000'}
375
+ fill={APP_FONT_COLOR}
370
376
  dx={textPaddingLollipop}
371
377
  textAnchor={textAnchorLollipop}
372
378
  verticalAnchor='middle'
@@ -137,7 +137,7 @@ const BarChartStackedHorizontal = () => {
137
137
  <Text
138
138
  x={`${bar.x + (config.isLollipopChart ? 15 : 5)}`} // padding
139
139
  y={bar.y + bar.height * 1.2}
140
- fill={'#000000'}
140
+ fill={APP_FONT_COLOR}
141
141
  textAnchor='start'
142
142
  verticalAnchor='start'
143
143
  >
@@ -16,6 +16,7 @@ import { isDateScale } from '@cdc/core/helpers/cove/date'
16
16
  import isNumber from '@cdc/core/helpers/isNumber'
17
17
  import createBarElement from '@cdc/core/components/createBarElement'
18
18
  import { APP_FONT_COLOR } from '@cdc/core/helpers/constants'
19
+ import { isMobileFontViewport } from '@cdc/core/helpers/viewports'
19
20
  // Third party libraries
20
21
  import chroma from 'chroma-js'
21
22
  // Types
@@ -45,6 +46,7 @@ export const BarChartVertical = () => {
45
46
  const {
46
47
  colorScale,
47
48
  config,
49
+ currentViewport,
48
50
  dashboardConfig,
49
51
  tableData,
50
52
  formatDate,
@@ -123,8 +125,20 @@ export const BarChartVertical = () => {
123
125
  seriesHighlight.indexOf(bar.key) !== -1
124
126
 
125
127
  let barGroupWidth = seriesScale.range()[1] - seriesScale.range()[0]
126
- const defaultBarHeight = Math.abs(yScale(bar.value) - yScale(scaleVal))
127
- const defaultBarY = bar.value >= 0 && isNumber(bar.value) ? bar.y : yScale(0)
128
+ let defaultBarHeight = Math.abs(yScale(bar.value) - yScale(scaleVal))
129
+ let defaultBarY = bar.value >= 0 && isNumber(bar.value) ? bar.y : yScale(0)
130
+
131
+ const MINIMUM_BAR_HEIGHT = 3
132
+ if (
133
+ bar.value >= 0 &&
134
+ isNumber(bar.value) &&
135
+ barGroup.bars.length === 1 &&
136
+ defaultBarHeight < MINIMUM_BAR_HEIGHT
137
+ ) {
138
+ defaultBarHeight = MINIMUM_BAR_HEIGHT
139
+ defaultBarY = yScale(0) - MINIMUM_BAR_HEIGHT
140
+ }
141
+
128
142
  let barWidth = config.isLollipopChart ? lollipopBarWidth : seriesScale.bandwidth()
129
143
  let barX =
130
144
  bar.x +
@@ -159,7 +173,7 @@ export const BarChartVertical = () => {
159
173
  yAxisValue
160
174
  })
161
175
  // configure colors
162
- let labelColor = '#000000'
176
+ let labelColor = APP_FONT_COLOR
163
177
  labelColor = HighLightedBarUtils.checkFontColor(yAxisValue, highlightedBarValues, labelColor) // Set if background is transparent'
164
178
  const isRegularLollipopColor = config.isLollipopChart && config.lollipopColorStyle === 'regular'
165
179
  const isTwoToneLollipopColor = config.isLollipopChart && config.lollipopColorStyle === 'two-tone'
@@ -254,6 +268,8 @@ export const BarChartVertical = () => {
254
268
 
255
269
  const BAR_LABEL_PADDING = 10
256
270
 
271
+ const LABEL_FONT_SIZE = isMobileFontViewport(currentViewport) ? 13 : 16
272
+
257
273
  return (
258
274
  <Group display={hideGroup} key={`${barGroup.index}--${index}`}>
259
275
  <Group key={`bar-sub-group-${barGroup.index}-${barGroup.x0}-${barY}--${index}`}>
@@ -353,6 +369,7 @@ export const BarChartVertical = () => {
353
369
  y={barY - BAR_LABEL_PADDING}
354
370
  fill={labelColor}
355
371
  textAnchor='middle'
372
+ fontSize={LABEL_FONT_SIZE}
356
373
  >
357
374
  {testZeroValue(bar.value) ? '' : barDefaultLabel}
358
375
  </Text>
@@ -363,7 +380,7 @@ export const BarChartVertical = () => {
363
380
  y={barY - BAR_LABEL_PADDING}
364
381
  fill={labelColor}
365
382
  textAnchor='middle'
366
- fontSize={config.isLollipopChart ? null : barWidth / 2}
383
+ fontSize={config.isLollipopChart ? null : LABEL_FONT_SIZE}
367
384
  >
368
385
  {absentDataLabel}
369
386
  </Text>
@@ -6,28 +6,36 @@ import ConfigContext from '../../ConfigContext'
6
6
  import { Text } from '@visx/text'
7
7
  import { APP_FONT_SIZE } from '@cdc/core/helpers/constants'
8
8
  import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
9
- import { isDateScale } from '@cdc/core/helpers/cove/date'
10
- export interface ZoomBrushProps {
9
+ export interface BrushChartProps {
11
10
  xMax: number
12
11
  yMax: number
13
12
  brushPosition: { start: { x: number }; end: { x: number } }
14
13
  onBrushChange: (bounds: any) => void
15
14
  brushKey: number
15
+ brushHandleProps: { startValue: string; endValue: string; endPos: number; startPos: number }
16
+ brushRef: React.RefObject<BrushRef>
16
17
  }
17
18
 
18
- const ZoomBrush: FC<ZoomBrushProps> = ({ xMax, yMax, brushPosition, onBrushChange, brushKey }) => {
19
- const { tableData, config, parseDate, dashboardConfig } = useContext(ConfigContext)
20
- const brushRef = useRef(null)
19
+ const BrushChart: FC<BrushChartProps> = ({
20
+ xMax,
21
+ yMax,
22
+ brushPosition,
23
+ onBrushChange,
24
+ brushKey,
25
+ brushHandleProps,
26
+ brushRef
27
+ }) => {
28
+ const { tableData, config, dashboardConfig } = useContext(ConfigContext)
21
29
  const dataKey = config.xAxis.dataKey
22
30
  const borderRadius = 15
23
31
  const mappedDates: string[] = tableData.map(row => row[dataKey])
24
32
  const brushheight = 25
25
33
  const DASHBOARD_MARGIN = 50
26
34
  const BRUSH_HEIGHT_MULTIPLIER = 1.5
27
-
35
+ const range = config?.xAxis?.sortByRecentDate ? [xMax, 0] : [0, xMax]
28
36
  const xScale = scaleBand<string>({
29
- domain: mappedDates,
30
- range: [0, xMax],
37
+ domain: config?.xAxis?.sortByRecentDate ? mappedDates.reverse() : mappedDates,
38
+ range: range,
31
39
  paddingInner: 0.1,
32
40
  paddingOuter: 0.1
33
41
  })
@@ -52,6 +60,16 @@ const ZoomBrush: FC<ZoomBrushProps> = ({ xMax, yMax, brushPosition, onBrushChang
52
60
  <Group left={config.yAxis.size} top={calculateGroupTop()}>
53
61
  <rect fill='#949494' width={xMax} height={25} rx={borderRadius} pointerEvents='none' />
54
62
  <Brush
63
+ disableDraggingOverlay={false}
64
+ renderBrushHandle={props => (
65
+ <BrushHandle
66
+ left={Number(config.runtime.yAxis.size)}
67
+ pixelDistance={brushHandleProps.endPos - brushHandleProps.startPos}
68
+ textProps={brushHandleProps}
69
+ isBrushing={brushRef.current?.state.isBrushing}
70
+ {...props}
71
+ />
72
+ )}
55
73
  innerRef={brushRef}
56
74
  key={brushKey}
57
75
  xScale={xScale}
@@ -64,10 +82,47 @@ const ZoomBrush: FC<ZoomBrushProps> = ({ xMax, yMax, brushPosition, onBrushChang
64
82
  initialBrushPosition={brushPosition}
65
83
  selectedBoxStyle={style}
66
84
  onChange={onBrushChange}
67
- disableDraggingOverlay={true}
85
+ useWindowMoveEvents={true}
68
86
  />
69
87
  </Group>
70
88
  )
71
89
  }
72
90
 
73
- export default ZoomBrush
91
+ export default BrushChart
92
+
93
+ const BrushHandle = props => {
94
+ const { x, y, isBrushing, className, textProps } = props
95
+ const pathWidth = 8
96
+
97
+ // Flip the SVG path horizontally for the left handle
98
+ const isLeft = className.includes('left')
99
+ const transform = isLeft ? 'scale(-1, 1)' : 'translate(0,0)'
100
+ const textAnchor = isLeft ? 'end' : 'start'
101
+ const tooltipText = isLeft ? ` Drag edges to focus on a specific segment ` : ''
102
+ const textFontSize = APP_FONT_SIZE / 1.4
103
+ const textWidth = getTextWidth(textProps.startValue, `${textFontSize}px`)
104
+ const textPosLeft = x > 0 ? 0 : 55
105
+ const textPosRight = y < textProps.xMax ? 0 : -50
106
+ return (
107
+ <Group left={x + pathWidth / 2} top={-2}>
108
+ <Text
109
+ pointerEvents='visiblePainted'
110
+ dominantBaseline='hanging'
111
+ x={isLeft ? textPosLeft : textPosRight}
112
+ y={25}
113
+ verticalAnchor='start'
114
+ textAnchor={textAnchor}
115
+ fontSize={textFontSize}
116
+ >
117
+ {isLeft ? textProps.startValue : textProps.endValue}
118
+ </Text>
119
+ <path
120
+ cursor='ew-resize'
121
+ d='M0.5,10A6,6 0 0 1 6.5,16V14A6,6 0 0 1 0.5,20ZM2.5,18V12M4.5,18V12'
122
+ fill='#297EF1'
123
+ strokeWidth='1'
124
+ transform={transform}
125
+ />
126
+ </Group>
127
+ )
128
+ }
@@ -1,21 +1,51 @@
1
- import { useState, useEffect, useContext } from 'react'
1
+ import { useState, useEffect, useContext, useRef } from 'react'
2
2
  import ConfigContext, { ChartDispatchContext } from '../../ConfigContext'
3
- import ZoomBrush from './BrushChart'
3
+ import BrushChart from './BrushChart'
4
+ import { isDateScale } from '@cdc/core/helpers/cove/date'
5
+ import { BrushRef } from './types'
6
+
4
7
  const BrushController = ({ yMax, xMax }) => {
5
- const { tableData, config, parseDate, dashboardConfig } = useContext(ConfigContext)
8
+ const { tableData, config, parseDate, dashboardConfig, formatDate } = useContext(ConfigContext)
9
+ const [brushHandleProps, setBrushHandleProps] = useState({
10
+ startPos: 0,
11
+ endPos: 0,
12
+ startValue: '',
13
+ endValue: '',
14
+ xMax: xMax
15
+ })
6
16
  const dataKey = config.xAxis.dataKey
7
17
  const [brushKey, setBrushKey] = useState(0)
8
18
  const dispatch = useContext(ChartDispatchContext)
9
19
  const sharedFilters = dashboardConfig?.dashboard?.sharedFilters ?? []
10
20
  const isDashboardFilters = sharedFilters?.length > 0
21
+ const brushRef = useRef<BrushRef | null>(null)
22
+
11
23
  const [brushPosition, setBrushPosition] = useState({
12
24
  start: { x: 0 },
13
25
  end: { x: xMax }
14
26
  })
15
27
 
16
28
  const handleBrushChange = (bounds: any) => {
17
- const selected = bounds.xValues || []
29
+ if (!bounds) return dispatch({ type: 'SET_BRUSH_DATA', payload: [] })
30
+ const filteredValues = bounds?.xValues?.filter(val => val !== undefined)
31
+ if (filteredValues?.length === 0) dispatch({ type: 'SET_BRUSH_DATA', payload: [] })
32
+ const selected = bounds?.xValues || []
33
+
18
34
  const filteredData = tableData.filter(row => selected.includes(row[dataKey]))
35
+ const endValue = filteredValues
36
+ .slice()
37
+ .reverse()
38
+ .find(item => item !== undefined)
39
+ const startValue = filteredValues.find(item => item !== undefined)
40
+ const formatIfDate = value => (isDateScale(config.runtime.xAxis) ? formatDate(parseDate(value)) : value)
41
+
42
+ setBrushHandleProps(prev => ({
43
+ ...prev,
44
+ startPos: brushRef.current?.state.start.x,
45
+ endPos: brushRef.current?.state.end.x,
46
+ endValue: formatIfDate(endValue),
47
+ startValue: formatIfDate(startValue)
48
+ }))
19
49
  dispatch({ type: 'SET_BRUSH_DATA', payload: filteredData })
20
50
  }
21
51
 
@@ -27,7 +57,9 @@ const BrushController = ({ yMax, xMax }) => {
27
57
  }, [config.filters, config.exclusions, config.brush?.active, isDashboardFilters])
28
58
 
29
59
  return (
30
- <ZoomBrush
60
+ <BrushChart
61
+ brushRef={brushRef}
62
+ brushHandleProps={brushHandleProps}
31
63
  xMax={xMax}
32
64
  yMax={yMax}
33
65
  brushPosition={brushPosition}
@@ -0,0 +1,8 @@
1
+ export type BrushRef = {
2
+ reset: () => void
3
+ state: {
4
+ start: { x: number; y: number }
5
+ end: { x: number; y: number }
6
+ isBrushing: boolean
7
+ }
8
+ }
@@ -67,8 +67,8 @@ const PanelAnnotate: React.FC<PanelProps> = props => {
67
67
  config.xAxis.type === 'date'
68
68
  ? new Date(config?.data?.[0]?.[config.xAxis.dataKey]).getTime()
69
69
  : config.xAxis.type === 'categorical'
70
- ? '1/15/2016'
71
- : '',
70
+ ? '1/15/2016'
71
+ : '',
72
72
  yKey: '',
73
73
  dx: 20,
74
74
  dy: -20,
@@ -281,6 +281,7 @@ const SeriesDropdownConfidenceInterval = props => {
281
281
  const { config, updateConfig } = useContext(ConfigContext)
282
282
  const { series, index } = props
283
283
  const { getColumns } = useContext(SeriesContext)
284
+
284
285
  if (series.type !== 'Forecasting') return
285
286
 
286
287
  return (
@@ -289,18 +290,6 @@ const SeriesDropdownConfidenceInterval = props => {
289
290
  <fieldset>
290
291
  <Accordion allowZeroExpanded>
291
292
  {series?.confidenceIntervals?.map((ciGroup, ciIndex) => {
292
- const showInTooltip = ciGroup.showInTooltip ? ciGroup.showInTooltip : false
293
-
294
- const updateShowInTooltip = (e, seriesIndex, ciIndex) => {
295
- e.preventDefault()
296
- let copiedSeries = [...config.series]
297
- copiedSeries[seriesIndex].confidenceIntervals[ciIndex].showInTooltip = !showInTooltip
298
- updateConfig({
299
- ...config,
300
- series: copiedSeries
301
- })
302
- }
303
-
304
293
  return (
305
294
  <AccordionItem className='series-item series-item--chart' key={`${ciIndex}`}>
306
295
  <AccordionItemHeading className='series-item__title'>
@@ -312,6 +301,7 @@ const SeriesDropdownConfidenceInterval = props => {
312
301
  onClick={e => {
313
302
  e.preventDefault()
314
303
  const copiedIndex = [...config.series[index].confidenceIntervals]
304
+
315
305
  copiedIndex.splice(ciIndex, 1)
316
306
  const copyOfSeries = [...config.series] // copy the entire series array
317
307
  copyOfSeries[index] = { ...copyOfSeries[index], confidenceIntervals: [...copiedIndex] }
@@ -327,28 +317,6 @@ const SeriesDropdownConfidenceInterval = props => {
327
317
  </>
328
318
  </AccordionItemHeading>
329
319
  <AccordionItemPanel>
330
- <div className='input-group'>
331
- <label htmlFor='showInTooltip'>Show In Tooltip</label>
332
- <div
333
- className={'cove-input__checkbox--small'}
334
- onClick={e => updateShowInTooltip(e, index, ciIndex)}
335
- >
336
- <div
337
- className={`cove-input__checkbox-box${'blue' ? ' custom-color' : ''}`}
338
- style={{ backgroundColor: '' }}
339
- >
340
- {showInTooltip && <Check className='' style={{ fill: '#025eaa' }} />}
341
- </div>
342
- <input
343
- className='cove-input--hidden'
344
- type='checkbox'
345
- name={'showInTooltip'}
346
- checked={showInTooltip ? showInTooltip : false}
347
- readOnly
348
- />
349
- </div>
350
- </div>
351
-
352
320
  <InputSelect
353
321
  initial='Select an option'
354
322
  value={
@@ -17,6 +17,7 @@ import { isLegendWrapViewport } from '@cdc/core/helpers/viewports'
17
17
  import LegendLineShape from './LegendLine.Shape'
18
18
  import LegendGroup from './LegendGroup'
19
19
  import { getSeriesWithData } from '../../helpers/dataHelpers'
20
+ import { publishAnalyticsEvent } from '@cdc/core/helpers/metrics/helpers'
20
21
 
21
22
  const LEGEND_PADDING = 36
22
23
 
@@ -32,6 +33,7 @@ export interface LegendProps {
32
33
  skipId: string
33
34
  dimensions: DimensionsType // for responsive width legend
34
35
  transformedData: any
36
+ interactionLabel: string
35
37
  }
36
38
 
37
39
  /* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
@@ -47,7 +49,8 @@ const Legend: React.FC<LegendProps> = forwardRef(
47
49
  formatLabels,
48
50
  skipId = 'legend',
49
51
  dimensions,
50
- transformedData: data
52
+ transformedData: data,
53
+ interactionLabel = ''
51
54
  },
52
55
  ref
53
56
  ) => {
@@ -137,11 +140,23 @@ const Legend: React.FC<LegendProps> = forwardRef(
137
140
  onKeyDown={e => {
138
141
  if (e.key === 'Enter') {
139
142
  e.preventDefault()
143
+ publishAnalyticsEvent(
144
+ `chart_legend_item_toggled--${legend.behavior}-mode`,
145
+ 'keydown',
146
+ `${interactionLabel}|${label.text}`,
147
+ 'chart'
148
+ )
140
149
  highlight(label)
141
150
  }
142
151
  }}
143
152
  onClick={e => {
144
153
  e.preventDefault()
154
+ publishAnalyticsEvent(
155
+ `chart_legend_item_toggled--${legend.behavior}-mode`,
156
+ 'click',
157
+ `${interactionLabel}|${label.text}`,
158
+ 'chart'
159
+ )
145
160
  highlight(label)
146
161
  }}
147
162
  role='button'
@@ -21,7 +21,8 @@ const Legend = forwardRef((props, ref) => {
21
21
  transformedData
22
22
  } = useContext(ConfigContext)
23
23
  if (!config.legend) return null
24
- // create fn to reverse labels while legend is Bottom. Legend-right , legend-left works by default.
24
+ // create fn to reverse labels while legend is Bottom. Legend-right , legend-left works by default
25
+ const { interactionLabel } = props
25
26
 
26
27
  const createLegendLabels = createFormatLabels(config, tableData, data, colorScale)
27
28
 
@@ -40,6 +41,7 @@ const Legend = forwardRef((props, ref) => {
40
41
  handleShowAll={handleShowAll}
41
42
  currentViewport={currentViewport}
42
43
  formatLabels={createLegendLabels}
44
+ interactionLabel={interactionLabel}
43
45
  />
44
46
  </Fragment>
45
47
  )