@cdc/chart 4.24.1 → 4.24.3

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 (82) hide show
  1. package/dist/cdcchart.js +48948 -37923
  2. package/examples/{private/combo.json → chart-regression-1.json} +40 -31
  3. package/examples/chart-regression-2.json +2360 -0
  4. package/examples/feature/filters/url-filter.json +1076 -0
  5. package/examples/feature/line/line-chart-preliminary.json +84 -37
  6. package/examples/feature/line/line-chart.json +2 -1
  7. package/examples/feature/regions/index.json +55 -5
  8. package/examples/feature/sankey/sankey-example-data.json +1364 -0
  9. package/examples/feature/sankey/sankey_chart_data.csv +20 -0
  10. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +306 -19
  11. package/examples/sparkline.json +868 -0
  12. package/index.html +128 -121
  13. package/package.json +4 -2
  14. package/src/CdcChart.tsx +73 -38
  15. package/src/_stories/ChartEditor.stories.tsx +15 -4
  16. package/src/_stories/_mock/pie_config.json +4 -3
  17. package/src/_stories/_mock/url_filter.json +1076 -0
  18. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +2 -1
  19. package/src/components/AreaChart/components/AreaChart.jsx +2 -25
  20. package/src/components/BarChart/components/BarChart.Horizontal.tsx +39 -49
  21. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +36 -56
  22. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +36 -41
  23. package/src/components/BarChart/components/BarChart.Vertical.tsx +48 -64
  24. package/src/components/BoxPlot/BoxPlot.jsx +11 -9
  25. package/src/components/DeviationBar.jsx +3 -3
  26. package/src/components/EditorPanel/EditorPanel.tsx +1717 -1961
  27. package/src/components/EditorPanel/EditorPanelContext.ts +40 -0
  28. package/src/components/EditorPanel/components/Panels/Panel.BoxPlot.tsx +148 -0
  29. package/src/components/EditorPanel/components/{Panel.ForestPlotSettings.tsx → Panels/Panel.ForestPlotSettings.tsx} +16 -7
  30. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +160 -0
  31. package/src/components/EditorPanel/components/{Panel.Regions.tsx → Panels/Panel.Regions.tsx} +6 -6
  32. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +108 -0
  33. package/src/components/EditorPanel/components/{Panel.Series.tsx → Panels/Panel.Series.tsx} +50 -6
  34. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +338 -0
  35. package/src/components/EditorPanel/components/Panels/index.tsx +19 -0
  36. package/src/components/EditorPanel/components/panels.scss +11 -0
  37. package/src/components/EditorPanel/editor-panel.scss +1 -13
  38. package/src/components/EditorPanel/useEditorPermissions.js +44 -13
  39. package/src/components/Legend/Legend.Component.tsx +207 -0
  40. package/src/components/Legend/Legend.tsx +8 -327
  41. package/src/components/Legend/helpers/createFormatLabels.tsx +140 -0
  42. package/src/components/LineChart/LineChartProps.ts +2 -1
  43. package/src/components/LineChart/components/LineChart.Circle.tsx +85 -52
  44. package/src/components/LineChart/helpers.ts +3 -3
  45. package/src/components/LineChart/index.tsx +99 -23
  46. package/src/components/LinearChart.jsx +12 -33
  47. package/src/components/PairedBarChart.jsx +10 -12
  48. package/src/components/PieChart/PieChart.tsx +80 -27
  49. package/src/components/Regions/components/Regions.tsx +120 -69
  50. package/src/components/Sankey/index.tsx +434 -0
  51. package/src/components/Sankey/sankey.scss +153 -0
  52. package/src/components/Sankey/types/index.ts +16 -0
  53. package/src/components/ScatterPlot/ScatterPlot.jsx +1 -0
  54. package/src/components/Sparkline/{SparkLine.jsx → components/SparkLine.tsx} +14 -30
  55. package/src/components/Sparkline/index.scss +3 -0
  56. package/src/components/Sparkline/index.tsx +1 -1
  57. package/src/components/ZoomBrush.tsx +2 -1
  58. package/src/data/initial-state.js +51 -4
  59. package/src/helpers/computeMarginBottom.ts +4 -3
  60. package/src/helpers/tests/computeMarginBottom.test.ts +2 -1
  61. package/src/hooks/useBarChart.js +5 -2
  62. package/src/hooks/useHighlightedBars.js +1 -1
  63. package/src/hooks/useMinMax.ts +3 -3
  64. package/src/hooks/useScales.ts +28 -18
  65. package/src/hooks/useTooltip.tsx +19 -14
  66. package/src/scss/main.scss +8 -96
  67. package/src/types/ChartConfig.ts +47 -20
  68. package/src/types/ChartContext.ts +17 -4
  69. package/src/types/Label.ts +7 -0
  70. package/examples/private/chart-t.json +0 -3740
  71. package/examples/private/epi-data.csv +0 -13
  72. package/examples/private/epi-data.json +0 -62
  73. package/examples/private/epi.json +0 -403
  74. package/examples/private/occupancy.json +0 -109283
  75. package/examples/private/prod-line-config.json +0 -401
  76. package/examples/private/region-data.json +0 -822
  77. package/examples/private/region-testing.json +0 -312
  78. package/examples/private/scaling.json +0 -45325
  79. package/examples/private/testing-data.json +0 -1739
  80. package/examples/private/testing.json +0 -816
  81. package/src/components/EditorPanel/components/Panel.DateHighlighting.tsx +0 -109
  82. package/src/components/EditorPanel/components/Panels.tsx +0 -13
@@ -0,0 +1,207 @@
1
+ import parse from 'html-react-parser'
2
+ import { LegendOrdinal, LegendItem, LegendLabel } from '@visx/legend'
3
+ import LegendCircle from '@cdc/core/components/LegendCircle'
4
+ import Button from '@cdc/core/components/elements/Button'
5
+
6
+ import useLegendClasses from '../../hooks/useLegendClasses'
7
+ import { useHighlightedBars } from '../../hooks/useHighlightedBars'
8
+ import { handleLineType } from '../../helpers/handleLineType'
9
+ import { Line } from '@visx/shape'
10
+ import { scaleOrdinal } from '@visx/scale'
11
+ import { Label } from '../../types/Label'
12
+ import { ChartConfig } from '../../types/ChartConfig'
13
+ import { ColorScale } from '../../types/ChartContext'
14
+ import { Group } from '@visx/group'
15
+ import { forwardRef } from 'react'
16
+
17
+ interface LegendProps {
18
+ config: ChartConfig
19
+ colorScale: ColorScale
20
+ seriesHighlight: string[]
21
+ highlight: Function
22
+ highlightReset: Function
23
+ currentViewport: string
24
+ formatLabels: (labels: Label[]) => Label[]
25
+ ref: React.Ref<() => void>
26
+ }
27
+
28
+ /* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
29
+ const Legend: React.FC<LegendProps> = forwardRef(({ config, colorScale, seriesHighlight, highlight, highlightReset, currentViewport, formatLabels }, ref) => {
30
+ const { innerClasses, containerClasses } = useLegendClasses(config)
31
+ const { runtime, orientation, legend } = config
32
+ if (!legend) return null
33
+ // create fn to reverse labels while legend is Bottom. Legend-right , legend-left works by default.
34
+ const displayScale = scaleOrdinal({
35
+ domain: config.suppressedData?.map(d => d.label),
36
+ range: ['none'],
37
+ unknown: 'block'
38
+ })
39
+
40
+ const renderDashes = style => {
41
+ const dashCount = style === 'Dashed Small' ? 3 : 2
42
+ const dashClass = `dashes ${style.toLowerCase().replace(' ', '-')}`
43
+
44
+ return (
45
+ <div className={dashClass}>
46
+ {Array.from({ length: dashCount }, (_, i) => (
47
+ <span key={i}>-</span>
48
+ ))}
49
+ </div>
50
+ )
51
+ }
52
+ const renderDashesOrCircle = style => {
53
+ if (['Dashed Small', 'Dashed Medium', 'Dashed Large'].includes(style)) {
54
+ return renderDashes(style)
55
+ } else if (style === 'Open Circles') {
56
+ return <div className='dashes open-circles'></div>
57
+ }
58
+ }
59
+
60
+ const isBottomOrSmallViewport = legend.position === 'bottom' || ['sm', 'xs', 'xxs'].includes(currentViewport)
61
+
62
+ const legendClasses = {
63
+ marginBottom: isBottomOrSmallViewport ? '15px' : '0px',
64
+ marginTop: isBottomOrSmallViewport && orientation === 'horizontal' ? `${config.yAxis.label && config.isResponsiveTicks ? config.dynamicMarginTop : config.runtime.xAxis.size}px` : `${isBottomOrSmallViewport ? config.dynamicMarginTop + 15 : 0}px`
65
+ }
66
+
67
+ const { HighLightedBarUtils } = useHighlightedBars(config)
68
+
69
+ let highLightedLegendItems = HighLightedBarUtils.findDuplicates(config.highlightedBarValues)
70
+
71
+ return (
72
+ <aside ref={ref} style={legendClasses} id='legend' className={containerClasses.join(' ')} role='region' aria-label='legend' tabIndex={0}>
73
+ {legend.label && <h3>{parse(legend.label)}</h3>}
74
+ {legend.description && <p>{parse(legend.description)}</p>}
75
+ <LegendOrdinal scale={colorScale} itemDirection='row' labelMargin='0 20px 0 0' shapeMargin='0 10px 0'>
76
+ {labels => {
77
+ return (
78
+ <>
79
+ <div className={innerClasses.join(' ')}>
80
+ {formatLabels(labels as Label[]).map((label, i) => {
81
+ let className = ['legend-item', `legend-text--${label.text.replace(' ', '').toLowerCase()}`]
82
+ let itemName = label.datum
83
+
84
+ // Filter excluded data keys from legend
85
+ if (config.exclusions.active && config.exclusions.keys?.includes(itemName)) {
86
+ return null
87
+ }
88
+
89
+ if (runtime.seriesLabels) {
90
+ let index = config.runtime.seriesLabelsAll.indexOf(itemName)
91
+ itemName = config.runtime.seriesKeys[index]
92
+
93
+ if (runtime?.forecastingSeriesKeys?.length > 0) {
94
+ itemName = label.text
95
+ }
96
+ }
97
+
98
+ if (seriesHighlight.length > 0 && false === seriesHighlight.includes(itemName)) {
99
+ className.push('inactive')
100
+ }
101
+
102
+ return (
103
+ <LegendItem
104
+ className={className.join(' ')}
105
+ tabIndex={0}
106
+ key={`legend-quantile-${i}`}
107
+ onKeyDown={e => {
108
+ if (e.key === 'Enter') {
109
+ e.preventDefault()
110
+ highlight(label)
111
+ }
112
+ }}
113
+ onClick={e => {
114
+ e.preventDefault()
115
+ highlight(label)
116
+ }}
117
+ role='button'
118
+ >
119
+ {config.visualizationType === 'Line' && config.legend.lineMode ? (
120
+ <svg width={40} height={20}>
121
+ <Line from={{ x: 10, y: 10 }} to={{ x: 40, y: 10 }} stroke={label.value} strokeWidth={2} strokeDasharray={handleLineType(config.series[i]?.type ? config.series[i]?.type : '')} />
122
+ </svg>
123
+ ) : (
124
+ <div style={{ display: 'flex', flexDirection: 'column' }}>
125
+ <LegendCircle margin='0' fill={label.value} display={displayScale(label.datum)} />
126
+ <div style={{ marginTop: '2px', marginRight: '6px' }}>{label.icon}</div>
127
+ </div>
128
+ )}
129
+
130
+ <LegendLabel align='left' margin='0 0 0 4px'>
131
+ {label.text}
132
+ </LegendLabel>
133
+ </LegendItem>
134
+ )
135
+ })}
136
+
137
+ {highLightedLegendItems.map((bar, i) => {
138
+ // if duplicates only return first item
139
+ let className = 'legend-item'
140
+ let itemName = bar.legendLabel
141
+
142
+ if (!itemName) return false
143
+ if (seriesHighlight.length > 0 && false === seriesHighlight.includes(itemName)) {
144
+ className += ' inactive'
145
+ }
146
+ return (
147
+ <LegendItem
148
+ className={className}
149
+ tabIndex={0}
150
+ key={`legend-quantile-${i}`}
151
+ onKeyDown={e => {
152
+ if (e.key === 'Enter') {
153
+ e.preventDefault()
154
+ highlight(bar.legendLabel)
155
+ }
156
+ }}
157
+ onClick={e => {
158
+ e.preventDefault()
159
+ highlight(bar.legendLabel)
160
+ }}
161
+ >
162
+ <LegendCircle fill='transparent' borderColor={bar.color ? bar.color : `rgba(255, 102, 1)`} />{' '}
163
+ <LegendLabel align='left' margin='0 0 0 4px'>
164
+ {bar.legendLabel ? bar.legendLabel : bar.value}
165
+ </LegendLabel>
166
+ </LegendItem>
167
+ )
168
+ })}
169
+ </div>
170
+
171
+ <>
172
+ {config?.preliminaryData?.some(pd => pd.label) && ['Line', 'Combo'].includes(config.visualizationType) && (
173
+ <>
174
+ <hr></hr>
175
+ <div className={config.legend.singleRow && isBottomOrSmallViewport ? 'legend-container__inner bottom single-row' : ''}>
176
+ {config?.preliminaryData?.map((pd, index) => {
177
+ return (
178
+ <>
179
+ {pd.label && (
180
+ <div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center' }}>
181
+ <svg style={{ width: '50px' }} key={index} height={'23px'}>
182
+ {pd.style.includes('Dashed') ? <Line from={{ x: 10, y: 10 }} to={{ x: 40, y: 10 }} stroke={'#000'} strokeWidth={2} strokeDasharray={handleLineType(pd.style)} /> : <circle r={6} strokeWidth={2} stroke={'#000'} cx={22} cy={10} fill='transparent' />}
183
+ </svg>
184
+ <span> {pd.label}</span>
185
+ </div>
186
+ )}
187
+ </>
188
+ )
189
+ })}
190
+ </div>
191
+ </>
192
+ )}
193
+ </>
194
+ </>
195
+ )
196
+ }}
197
+ </LegendOrdinal>
198
+ {seriesHighlight.length > 0 && (
199
+ <Button onClick={labels => highlightReset(labels)} style={{ marginTop: '1rem' }}>
200
+ Reset
201
+ </Button>
202
+ )}
203
+ </aside>
204
+ )
205
+ })
206
+
207
+ export default Legend
@@ -1,29 +1,10 @@
1
- import { useContext } from 'react'
1
+ import { useContext, forwardRef } from 'react'
2
2
  import ConfigContext from '../../ConfigContext'
3
- import parse from 'html-react-parser'
4
- import { LegendOrdinal, LegendItem, LegendLabel } from '@visx/legend'
5
- import LegendCircle from '@cdc/core/components/LegendCircle'
6
-
7
- import useLegendClasses from '../../hooks/useLegendClasses'
8
- import { useHighlightedBars } from '../../hooks/useHighlightedBars'
9
- import { handleLineType } from '../../helpers/handleLineType'
10
- import { Line } from '@visx/shape'
11
- import { colorPalettesChart as colorPalettes, sequentialPalettes, twoColorPalette } from '@cdc/core/data/colorPalettes'
12
- import { scaleOrdinal } from '@visx/scale'
13
- import { FaStar } from 'react-icons/fa'
14
- import { Text } from '@visx/text'
15
- import { Group } from '@visx/group'
16
-
17
- type Label = {
18
- datum: string
19
- index: number
20
- text: string
21
- value: string
22
- icon?: any
23
- }
3
+ import LegendComponent from './Legend.Component'
4
+ import { createFormatLabels } from './helpers/createFormatLabels'
24
5
 
25
6
  /* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
26
- const Legend = () => {
7
+ const Legend = forwardRef((props, ref) => {
27
8
  // prettier-ignore
28
9
  const {
29
10
  config,
@@ -36,312 +17,12 @@ const Legend = () => {
36
17
  currentViewport
37
18
  } = useContext(ConfigContext)
38
19
 
39
- const { innerClasses, containerClasses } = useLegendClasses(config)
40
- const { visualizationType, visualizationSubType, series, runtime, orientation, legend } = config
20
+ if (!config.legend) return null
41
21
  // create fn to reverse labels while legend is Bottom. Legend-right , legend-left works by default.
42
- const reverseLabels = labels => (config.legend.reverseLabelOrder && config.legend.position === 'bottom' ? labels.reverse() : labels)
43
- const displayScale = scaleOrdinal({
44
- domain: config.suppressedData?.map(d => d.label),
45
- range: ['none'],
46
- unknown: 'block'
47
- })
48
-
49
- const renderDashes = style => {
50
- const dashCount = style === 'Dashed Small' ? 3 : 2
51
- const dashClass = `dashes ${style.toLowerCase().replace(' ', '-')}`
52
-
53
- return (
54
- <div className={dashClass}>
55
- {Array.from({ length: dashCount }, (_, i) => (
56
- <span key={i}>-</span>
57
- ))}
58
- </div>
59
- )
60
- }
61
- const renderDashesOrCircle = style => {
62
- if (['Dashed Small', 'Dashed Medium', 'Dashed Large'].includes(style)) {
63
- return renderDashes(style)
64
- } else if (style === 'Open Circles') {
65
- return <div className='dashes open-circles'></div>
66
- }
67
- }
68
- const createLegendLabels = (defaultLabels): Label[] => {
69
- const colorCode = config.legend?.colorCode
70
- if (visualizationType === 'Deviation Bar') {
71
- const [belowColor, aboveColor] = twoColorPalette[config.twoColor.palette]
72
- const labelBelow = {
73
- datum: 'X',
74
- index: 0,
75
- text: `Below ${config.xAxis.targetLabel}`,
76
- value: belowColor
77
- }
78
- const labelAbove = {
79
- datum: 'X',
80
- index: 1,
81
- text: `Above ${config.xAxis.targetLabel}`,
82
- value: aboveColor
83
- }
84
-
85
- return reverseLabels([labelBelow, labelAbove])
86
- }
87
- if (visualizationType === 'Bar' && visualizationSubType === 'regular' && colorCode && series?.length === 1) {
88
- let palette = colorPalettes[config.palette]
89
-
90
- while (tableData.length > palette.length) {
91
- palette = palette.concat(palette)
92
- }
93
- palette = palette.slice(0, data.length)
94
- //store unique values to Set by colorCode
95
- const set = new Set()
96
-
97
- tableData.forEach(d => set.add(d[colorCode]))
98
-
99
- // create labels with unique values
100
- const uniqueLabels = Array.from(set).map((val, i) => {
101
- const newLabel = {
102
- datum: val,
103
- index: i,
104
- text: val,
105
- value: palette[i]
106
- }
107
- return newLabel
108
- })
109
-
110
- return reverseLabels(uniqueLabels)
111
- }
112
-
113
- // get forecasting items inside of combo
114
- if (runtime?.forecastingSeriesKeys?.length > 0) {
115
- let seriesLabels = []
116
-
117
- //store unique values to Set by colorCode
118
- // loop through each stage/group/area on the chart and create a label
119
- config.runtime?.forecastingSeriesKeys?.map((outerGroup, index) => {
120
- return outerGroup?.stages?.map((stage, index) => {
121
- let colorValue = sequentialPalettes[stage.color]?.[2] ? sequentialPalettes[stage.color]?.[2] : colorPalettes[stage.color]?.[2] ? colorPalettes[stage.color]?.[2] : '#ccc'
122
-
123
- const newLabel = {
124
- datum: stage.key,
125
- index: index,
126
- text: stage.key,
127
- value: colorValue
128
- }
129
-
130
- seriesLabels.push(newLabel)
131
- })
132
- })
133
-
134
- // loop through bars for now to meet requirements.
135
- config.runtime.barSeriesKeys &&
136
- config.runtime.barSeriesKeys.forEach((bar, index) => {
137
- let colorValue = colorPalettes[config.palette][index] ? colorPalettes[config.palette][index] : '#ccc'
138
-
139
- const newLabel = {
140
- datum: bar,
141
- index: index,
142
- text: bar,
143
- value: colorValue
144
- }
145
-
146
- seriesLabels.push(newLabel)
147
- })
148
-
149
- return reverseLabels(seriesLabels)
150
- }
151
-
152
- // DEV-4161: replaceable series name in the legend
153
- const hasNewSeriesName = config.series.map(s => s.name).filter(item => item).length > 0
154
- if (hasNewSeriesName) {
155
- let palette = colorPalettes[config.palette]
156
-
157
- while (tableData.length > palette.length) {
158
- palette = palette.concat(palette)
159
- }
160
-
161
- palette = palette.slice(0, data.length)
162
- //store unique values to Set by colorCode
163
- const set = new Set()
164
-
165
- config.series.forEach(d => {
166
- set.add(d['name'] ? d['name'] : d['dataKey'])
167
- })
168
-
169
- // create labels with unique values
170
- const uniqueLabels = Array.from(set).map((val, i) => {
171
- const newLabel = {
172
- datum: val,
173
- index: i,
174
- text: val,
175
- value: colorScale(val)
176
- }
177
- return newLabel
178
- })
179
-
180
- return reverseLabels(uniqueLabels)
181
- }
182
-
183
- if ((config.visualizationType === 'Bar' || config.visualizationType === 'Combo') && config.visualizationSubType === 'regular' && config.suppressedData) {
184
- const lastIndex = defaultLabels.length - 1
185
- let newLabels = []
186
-
187
- config.suppressedData?.forEach(({ label, icon }, index) => {
188
- if (label && icon) {
189
- const newLabel = {
190
- datum: label,
191
- index: lastIndex + index,
192
- text: label,
193
- icon: <FaStar color='#000' size={15} />
194
- }
195
- newLabels.push(newLabel)
196
- }
197
- })
198
-
199
- return [...defaultLabels, ...newLabels]
200
- }
201
-
202
- return reverseLabels(defaultLabels)
203
- }
204
-
205
- const isBottomOrSmallViewport = legend.position === 'bottom' || ['sm', 'xs', 'xxs'].includes(currentViewport)
206
-
207
- const legendClasses = {
208
- marginBottom: isBottomOrSmallViewport ? '15px' : '0px',
209
- marginTop: isBottomOrSmallViewport && orientation === 'horizontal' ? `${config.yAxis.label && config.isResponsiveTicks ? config.dynamicMarginTop : config.runtime.xAxis.size}px` : `${isBottomOrSmallViewport ? config.dynamicMarginTop + 15 : 0}px`
210
- }
211
-
212
- const { HighLightedBarUtils } = useHighlightedBars(config)
213
-
214
- let highLightedLegendItems = HighLightedBarUtils.findDuplicates(config.highlightedBarValues)
215
- if (!legend) return null
216
-
217
- return (
218
- config.visualizationType !== 'Box Plot' && (
219
- <aside style={legendClasses} id='legend' className={containerClasses.join(' ')} role='region' aria-label='legend' tabIndex={0}>
220
- {legend.label && <h2>{parse(legend.label)}</h2>}
221
- {legend.description && <p>{parse(legend.description)}</p>}
222
- <LegendOrdinal scale={colorScale} itemDirection='row' labelMargin='0 20px 0 0' shapeMargin='0 10px 0'>
223
- {labels => {
224
- return (
225
- <>
226
- <div className={innerClasses.join(' ')}>
227
- {createLegendLabels(labels).map((label, i) => {
228
- let className = ['legend-item', `legend-text--${label.text.replace(' ', '').toLowerCase()}`]
229
- let itemName = label.datum
230
-
231
- // Filter excluded data keys from legend
232
- if (config.exclusions.active && config.exclusions.keys?.includes(itemName)) {
233
- return null
234
- }
235
-
236
- if (runtime.seriesLabels) {
237
- let index = config.runtime.seriesLabelsAll.indexOf(itemName)
238
- itemName = config.runtime.seriesKeys[index]
239
-
240
- if (runtime?.forecastingSeriesKeys?.length > 0) {
241
- itemName = label.text
242
- }
243
- }
244
-
245
- if (seriesHighlight.length > 0 && false === seriesHighlight.includes(itemName)) {
246
- className.push('inactive')
247
- }
248
-
249
- return (
250
- <LegendItem
251
- className={className.join(' ')}
252
- tabIndex={0}
253
- key={`legend-quantile-${i}`}
254
- onKeyPress={e => {
255
- if (e.key === 'Enter') {
256
- highlight(label)
257
- }
258
- }}
259
- onClick={() => {
260
- highlight(label)
261
- }}
262
- >
263
- {config.visualizationType === 'Line' && config.legend.lineMode ? (
264
- <svg width={40} height={20}>
265
- <Line from={{ x: 10, y: 10 }} to={{ x: 40, y: 10 }} stroke={label.value} strokeWidth={2} strokeDasharray={handleLineType(config.series[i]?.type ? config.series[i]?.type : '')} />
266
- </svg>
267
- ) : (
268
- <div style={{ display: 'flex', flexDirection: 'column' }}>
269
- <LegendCircle margin='0' fill={label.value} display={displayScale(label.datum)} />
270
- <div style={{ marginTop: '2px', marginRight: '6px' }}>{label.icon}</div>
271
- </div>
272
- )}
273
-
274
- <LegendLabel align='left' margin='0 0 0 4px'>
275
- {label.text}
276
- </LegendLabel>
277
- </LegendItem>
278
- )
279
- })}
280
22
 
281
- {highLightedLegendItems.map((bar, i) => {
282
- // if duplicates only return first item
283
- let className = 'legend-item'
284
- let itemName = bar.legendLabel
23
+ const createLegendLabels = createFormatLabels(config, tableData, data, colorScale)
285
24
 
286
- if (!itemName) return false
287
- if (seriesHighlight.length > 0 && false === seriesHighlight.includes(itemName)) {
288
- className += ' inactive'
289
- }
290
- return (
291
- <LegendItem
292
- className={className}
293
- tabIndex={0}
294
- key={`legend-quantile-${i}`}
295
- onKeyPress={e => {
296
- if (e.key === 'Enter') {
297
- highlight(bar.legendLabel)
298
- }
299
- }}
300
- onClick={() => {
301
- highlight(bar.legendLabel)
302
- }}
303
- >
304
- <LegendCircle fill='transparent' borderColor={bar.color ? bar.color : `rgba(255, 102, 1)`} />{' '}
305
- <LegendLabel align='left' margin='0 0 0 4px'>
306
- {bar.legendLabel ? bar.legendLabel : bar.value}
307
- </LegendLabel>
308
- </LegendItem>
309
- )
310
- })}
311
- {seriesHighlight.length > 0 && (
312
- <button className={`legend-reset ${config.theme}`} onClick={labels => highlightReset(labels)} tabIndex={0}>
313
- Reset
314
- </button>
315
- )}
316
- </div>
317
- <>
318
- {config.preliminaryData.some(pd => pd.label) && (
319
- <>
320
- <hr></hr>
321
- <div className={config.legend.singleRow && isBottomOrSmallViewport ? 'legend-container__inner bottom single-row' : 'dash-left'}>
322
- {config.preliminaryData.map((pd, index) => {
323
- return (
324
- <div className='dash-container' key={index}>
325
- {pd.label && (
326
- <>
327
- <div className='dash-inner'>{renderDashesOrCircle(pd.style)}</div>
328
- <div style={{ marginLeft: '7px' }}>{pd.label}</div>
329
- </>
330
- )}
331
- </div>
332
- )
333
- })}
334
- </div>
335
- </>
336
- )}
337
- </>
338
- </>
339
- )
340
- }}
341
- </LegendOrdinal>
342
- </aside>
343
- )
344
- )
345
- }
25
+ return !['Box Plot', 'Pie'].includes(config.visualizationType) && <LegendComponent ref={ref} config={config} colorScale={colorScale} seriesHighlight={seriesHighlight} highlight={highlight} highlightReset={highlightReset} currentViewport={currentViewport} formatLabels={createLegendLabels} />
26
+ })
346
27
 
347
28
  export default Legend