@cdc/chart 1.3.4 → 4.22.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +5 -5
  3. package/dist/cdcchart.js +6 -6
  4. package/examples/age-adjusted-rates.json +1486 -1218
  5. package/examples/case-rate-example-config.json +1 -1
  6. package/examples/covid-confidence-example-config.json +33 -33
  7. package/examples/covid-example-config.json +34 -34
  8. package/examples/covid-example-data-confidence.json +30 -30
  9. package/examples/covid-example-data.json +20 -20
  10. package/examples/cutoff-example-config.json +36 -34
  11. package/examples/cutoff-example-data.json +36 -36
  12. package/examples/date-exclusions-config.json +1 -1
  13. package/examples/dynamic-legends.json +125 -0
  14. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart-with-numbers-on-bar.json +192 -0
  15. package/examples/gallery/bar-chart-horizontal/horizontal-bar-chart.json +231 -0
  16. package/examples/gallery/bar-chart-horizontal/horizontal-stacked.json +240 -0
  17. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +137 -0
  18. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +80 -0
  19. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +81 -0
  20. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-with-confidence.json +68 -0
  21. package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +111 -0
  22. package/examples/gallery/lollipop/lollipop-style-horizontal.json +216 -0
  23. package/examples/gallery/paired-bar/paired-bar-chart.json +196 -0
  24. package/examples/horizontal-chart.json +36 -33
  25. package/examples/horizontal-stacked-bar-chart.json +34 -34
  26. package/examples/line-chart.json +75 -75
  27. package/examples/paired-bar-data.json +16 -14
  28. package/examples/paired-bar-example.json +48 -46
  29. package/examples/paired-bar-formatted.json +36 -36
  30. package/examples/planet-chart-horizontal-example-config.json +33 -33
  31. package/examples/planet-combo-example-config.json +34 -29
  32. package/examples/planet-example-config.json +35 -33
  33. package/examples/planet-example-data.json +56 -56
  34. package/examples/planet-pie-example-config.json +28 -26
  35. package/examples/private/filters.json +170 -0
  36. package/examples/private/line-test-data.json +22 -0
  37. package/examples/private/line-test-two.json +210 -0
  38. package/examples/private/line-test.json +102 -0
  39. package/examples/private/new.json +48800 -0
  40. package/examples/private/shawn.json +1106 -0
  41. package/examples/private/test.json +10123 -10123
  42. package/examples/private/yaxis-test.json +133 -0
  43. package/examples/private/yaxis-testing.csv +27 -0
  44. package/examples/private/yaxis.json +28 -0
  45. package/examples/stacked-vertical-bar-example.json +228 -0
  46. package/examples/temp-example-config.json +61 -54
  47. package/examples/temp-example-data.json +1 -1
  48. package/package.json +2 -2
  49. package/src/CdcChart.tsx +370 -458
  50. package/src/components/BarChart.tsx +449 -441
  51. package/src/components/DataTable.tsx +164 -180
  52. package/src/components/EditorPanel.js +1066 -663
  53. package/src/components/Legend.js +284 -0
  54. package/src/components/LineChart.tsx +114 -63
  55. package/src/components/LinearChart.tsx +394 -358
  56. package/src/components/PairedBarChart.tsx +216 -135
  57. package/src/components/PieChart.tsx +106 -135
  58. package/src/components/SparkLine.js +184 -205
  59. package/src/components/useIntersectionObserver.tsx +27 -0
  60. package/src/context.tsx +3 -3
  61. package/src/data/initial-state.js +44 -7
  62. package/src/hooks/useActiveElement.js +13 -13
  63. package/src/hooks/useChartClasses.js +41 -0
  64. package/src/hooks/useColorPalette.ts +56 -63
  65. package/src/hooks/useLegendClasses.js +28 -0
  66. package/src/hooks/useReduceData.ts +69 -37
  67. package/src/hooks/useRightAxis.js +25 -0
  68. package/src/hooks/useTopAxis.js +6 -0
  69. package/src/index.html +54 -55
  70. package/src/index.tsx +13 -16
  71. package/src/scss/DataTable.scss +5 -4
  72. package/src/scss/editor-panel.scss +103 -71
  73. package/src/scss/main.scss +277 -38
  74. package/src/scss/variables.scss +1 -1
  75. package/src/components/BarStackVertical.js +0 -0
@@ -0,0 +1,284 @@
1
+ import React, { useContext, useEffect } from 'react'
2
+ import Context from '../context'
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
+
9
+ const Legend = () => {
10
+ const { config, legend, colorScale, seriesHighlight, highlight, highlightReset, setSeriesHighlight, dynamicLegendItems, setDynamicLegendItems, transformedData: data, setFilteredData, colorPalettes, rawData, setConfig } = useContext(Context)
11
+
12
+ const { innerClasses, containerClasses } = useLegendClasses(config)
13
+
14
+ useEffect(() => {
15
+ if (dynamicLegendItems.length === 0) return
16
+
17
+ let itemsToHighlight = dynamicLegendItems.map(item => item.text)
18
+
19
+ setSeriesHighlight(itemsToHighlight)
20
+
21
+ let colsToKeep = [...itemsToHighlight]
22
+ let tmpLabels = []
23
+
24
+ rawData.map(dataItem => {
25
+ let tmp = {}
26
+ colsToKeep.map(col => {
27
+ tmp[col] = isNaN(dataItem[col]) ? dataItem[col] : dataItem[col]
28
+ })
29
+ return tmp
30
+ })
31
+
32
+ colsToKeep.map(col => {
33
+ tmpLabels[col] = col
34
+ })
35
+
36
+ if (dynamicLegendItems.length > 0) {
37
+ setConfig({
38
+ ...config,
39
+ runtime: {
40
+ ...config.runtime,
41
+ seriesKeys: colsToKeep,
42
+ seriesLabels: tmpLabels
43
+ }
44
+ })
45
+ }
46
+ }, [dynamicLegendItems])
47
+
48
+ useEffect(() => {
49
+ if (dynamicLegendItems.length === 0) {
50
+ // loop through all labels and add keys
51
+ let resetSeriesNames = [...config.runtime.seriesLabelsAll]
52
+ let tmpLabels = []
53
+ config.runtime.seriesLabelsAll.map(item => {
54
+ resetSeriesNames.map(col => {
55
+ tmpLabels[col] = col
56
+ })
57
+ })
58
+
59
+ setConfig({
60
+ ...config,
61
+ runtime: {
62
+ ...config.runtime,
63
+ seriesKeys: config.runtime.seriesLabelsAll,
64
+ seriesLabels: tmpLabels
65
+ }
66
+ })
67
+ }
68
+ }, [dynamicLegendItems])
69
+
70
+ const removeDynamicLegendItem = label => {
71
+ let newLegendItems = dynamicLegendItems.filter(item => item.text !== label.text)
72
+ let newLegendItemsText = newLegendItems.map(item => item.text)
73
+ setDynamicLegendItems(newLegendItems)
74
+ setSeriesHighlight(newLegendItemsText)
75
+ }
76
+ const handleDynamicLegendChange = e => {
77
+ setDynamicLegendItems([...dynamicLegendItems, JSON.parse(e.target.value)])
78
+ }
79
+
80
+ const createLegendLabels = (data, defaultLabels) => {
81
+ const colorCode = config.legend?.colorCode
82
+ if (config.visualizationType !== 'Bar' || config.visualizationSubType !== 'regular' || !colorCode || config.series?.length > 1) {
83
+ return defaultLabels
84
+ }
85
+ let palette = colorPalettes[config.palette]
86
+
87
+ while (data.length > palette.length) {
88
+ palette = palette.concat(palette)
89
+ }
90
+ palette = palette.slice(0, data.length)
91
+ //store uniq values to Set by colorCode
92
+ const set = new Set()
93
+
94
+ data.forEach(d => set.add(d[colorCode]))
95
+
96
+ // create labels with uniq values
97
+ const uniqeLabels = Array.from(set).map((val, i) => {
98
+ const newLabel = {
99
+ datum: val,
100
+ index: i,
101
+ text: val,
102
+ value: palette[i]
103
+ }
104
+ return newLabel
105
+ })
106
+
107
+ return uniqeLabels
108
+ }
109
+
110
+ if (!legend) return
111
+
112
+ if (!legend.dynamicLegend)
113
+ return (
114
+ <aside id='legend' className={containerClasses.join(' ')} role='region' aria-label='legend' tabIndex={0}>
115
+ {legend.label && <h2>{parse(legend.label)}</h2>}
116
+ {legend.description && <p>{parse(legend.description)}</p>}
117
+ <LegendOrdinal scale={colorScale} itemDirection='row' labelMargin='0 20px 0 0' shapeMargin='0 10px 0'>
118
+ {labels => (
119
+ <div className={innerClasses.join(' ')}>
120
+ {createLegendLabels(data, labels).map((label, i) => {
121
+ let className = 'legend-item'
122
+ let itemName = label.datum
123
+
124
+ // Filter excluded data keys from legend
125
+ if (config.exclusions.active && config.exclusions.keys?.includes(itemName)) {
126
+ return
127
+ }
128
+
129
+ if (config.runtime.seriesLabels) {
130
+ let index = config.runtime.seriesLabelsAll.indexOf(itemName)
131
+ itemName = config.runtime.seriesKeys[index]
132
+ }
133
+
134
+ if (seriesHighlight.length > 0 && false === seriesHighlight.includes(itemName)) {
135
+ className += ' inactive'
136
+ }
137
+
138
+ return (
139
+ <LegendItem
140
+ className={className}
141
+ tabIndex={0}
142
+ key={`legend-quantile-${i}`}
143
+ onKeyPress={e => {
144
+ if (e.key === 'Enter') {
145
+ highlight(label)
146
+ }
147
+ }}
148
+ onClick={() => {
149
+ highlight(label)
150
+ }}
151
+ >
152
+ <LegendCircle fill={label.value} />
153
+ <LegendLabel align='left' margin='0 0 0 4px'>
154
+ {label.text}
155
+ </LegendLabel>
156
+ </LegendItem>
157
+ )
158
+ })}
159
+ {seriesHighlight.length > 0 && (
160
+ <button className={`legend-reset ${config.theme}`} onClick={labels => highlightReset(labels)} tabIndex={0}>
161
+ Reset
162
+ </button>
163
+ )}
164
+ </div>
165
+ )}
166
+ </LegendOrdinal>
167
+ </aside>
168
+ )
169
+
170
+ return (
171
+ <aside id='legend' className={containerClasses.join(' ')} role='region' aria-label='legend' tabIndex={0}>
172
+ {legend.label && <h2>{parse(legend.label)}</h2>}
173
+ {legend.description && <p>{parse(legend.description)}</p>}
174
+
175
+ <LegendOrdinal scale={colorScale} itemDirection='row' labelMargin='0 20px 0 0' shapeMargin='0 10px 0'>
176
+ {labels => {
177
+ if (
178
+ Number(config.legend.dynamicLegendItemLimit) > dynamicLegendItems.length && // legend items are less than limit
179
+ dynamicLegendItems.length !== config.runtime.seriesLabelsAll.length
180
+ ) {
181
+ // legend items are equal to series length
182
+ return (
183
+ <select className='dynamic-legend-dropdown' onChange={e => handleDynamicLegendChange(e)}>
184
+ <option className={'all'} tabIndex={0} value={JSON.stringify({ text: config.legend.dynamicLegendDefaultText })}>
185
+ {config.legend.dynamicLegendDefaultText}
186
+ </option>
187
+ {labels.map((label, i) => {
188
+ let className = 'legend-item'
189
+ let itemName = label.datum
190
+ let inDynamicList = false
191
+
192
+ // Filter excluded data keys from legend
193
+ if (config.exclusions.active && config.exclusions.keys?.includes(itemName)) {
194
+ return
195
+ }
196
+
197
+ if (config.runtime.seriesLabels) {
198
+ let index = config.runtime.seriesLabelsAll.indexOf(itemName)
199
+ itemName = config.runtime.seriesKeys[index]
200
+ }
201
+
202
+ if (seriesHighlight.length > 0 && false === seriesHighlight.includes(itemName)) {
203
+ className += ' inactive'
204
+ }
205
+
206
+ dynamicLegendItems.map(listItem => {
207
+ if (listItem.text === label.text) {
208
+ inDynamicList = true
209
+ }
210
+ })
211
+
212
+ if (inDynamicList) return true
213
+ let palette = colorPalettes[config.palette]
214
+
215
+ label.value = palette[dynamicLegendItems.length]
216
+
217
+ return (
218
+ <option className={className} tabIndex={0} value={JSON.stringify(label)}>
219
+ {label.text}
220
+ </option>
221
+ )
222
+ })}
223
+ </select>
224
+ )
225
+ } else {
226
+ return config.legend.dynamicLegendItemLimitMessage
227
+ }
228
+ }}
229
+ </LegendOrdinal>
230
+
231
+ <div className='dynamic-legend-list'>
232
+ {dynamicLegendItems.map((label, i) => {
233
+ let className = ['legend-item']
234
+ let itemName = label.text
235
+ let palette = colorPalettes[config.palette]
236
+
237
+ // Filter excluded data keys from legend
238
+ if (config.exclusions.active && config.exclusions.keys?.includes(itemName)) {
239
+ return
240
+ }
241
+
242
+ if (config.runtime.seriesLabels && !config.legend.dynamicLegend) {
243
+ let index = config.runtime.seriesLabelsAll.indexOf(itemName)
244
+ itemName = config.runtime.seriesKeys[index]
245
+ }
246
+
247
+ if (seriesHighlight.length > 0 && !seriesHighlight.includes(itemName)) {
248
+ className.push('inactive')
249
+ }
250
+
251
+ if (seriesHighlight.length === 0 && config.legend.dynamicLegend) {
252
+ className.push('inactive')
253
+ }
254
+
255
+ return (
256
+ <>
257
+ <LegendItem className={className.join(' ')} tabIndex={0} key={`dynamic-legend-item-${i}`} alignItems='center'>
258
+ <button
259
+ className='btn-wrapper'
260
+ onClick={() => {
261
+ highlight(label)
262
+ }}
263
+ >
264
+ <LegendCircle fill={palette[i]} config={config} />
265
+ <LegendLabel align='space-between' margin='4px 0 0 4px'>
266
+ {label.text}
267
+ </LegendLabel>
268
+ </button>
269
+ <button onClick={() => removeDynamicLegendItem(label)}>x</button>
270
+ </LegendItem>
271
+ </>
272
+ )
273
+ })}
274
+ </div>
275
+ {seriesHighlight.length < dynamicLegendItems.length && (
276
+ <button className={`legend-reset legend-reset--dynamic ${config.theme}`} onClick={highlightReset} tabIndex={0}>
277
+ Reset
278
+ </button>
279
+ )}
280
+ </aside>
281
+ )
282
+ }
283
+
284
+ export default Legend
@@ -1,76 +1,127 @@
1
- import React, { useContext } from 'react';
1
+ import React, { useContext } from 'react'
2
2
 
3
- import * as allCurves from '@visx/curve';
4
- import { Group } from '@visx/group';
5
- import { LinePath } from '@visx/shape';
6
- import { Text } from '@visx/text';
3
+ import * as allCurves from '@visx/curve'
4
+ import { Group } from '@visx/group'
5
+ import { LinePath } from '@visx/shape'
6
+ import { Text } from '@visx/text'
7
7
 
8
- import ErrorBoundary from '@cdc/core/components/ErrorBoundary';
8
+ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
9
9
 
10
- import Context from '../context';
10
+ import Context from '../context'
11
11
 
12
- export default function LineChart({ xScale, yScale, getXAxisData, getYAxisData }) {
13
- const { transformedData: data, colorScale, seriesHighlight, config, formatNumber,formatDate,parseDate } = useContext<any>(Context);
12
+ import useRightAxis from '../hooks/useRightAxis'
13
+
14
+ export default function LineChart({ xScale, yScale, getXAxisData, getYAxisData, xMax, yMax, seriesStyle = 'Line' }) {
15
+ const { colorPalettes, transformedData: data, colorScale, seriesHighlight, config, formatNumber, formatDate, parseDate, updateConfig } = useContext<any>(Context)
16
+ const { yScaleRight } = useRightAxis({ config, yMax, data, updateConfig })
17
+
18
+ const handleLineType = lineType => {
19
+ switch (lineType) {
20
+ case 'dashed-sm':
21
+ return '5 5'
22
+ case 'dashed-md':
23
+ return '10 5'
24
+ case 'dashed-lg':
25
+ return '15 5'
26
+ default:
27
+ return 0
28
+ }
29
+ }
14
30
 
15
31
  return (
16
- <ErrorBoundary component="LineChart">
32
+ <ErrorBoundary component='LineChart'>
17
33
  <Group left={config.runtime.yAxis.size}>
18
- { (config.runtime.lineSeriesKeys || config.runtime.seriesKeys).map((seriesKey, index) => (
19
- <Group
20
- key={`series-${seriesKey}`}
21
- opacity={config.legend.behavior === "highlight" && seriesHighlight.length > 0 && seriesHighlight.indexOf(seriesKey) === -1 ? 0.5 : 1}
22
- display={config.legend.behavior === "highlight" || seriesHighlight.length === 0 || seriesHighlight.indexOf(seriesKey) !== -1 ? 'block' : 'none'}
23
- >
24
- { data.map((d, dataIndex) => {
25
- const xAxisValue = config.runtime.xAxis.type==='date' ? formatDate(parseDate(d[config.runtime.xAxis.dataKey])) : d[config.runtime.xAxis.dataKey];
26
- let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${formatNumber(getYAxisData(d, seriesKey))}` : formatNumber(getYAxisData(d, seriesKey))
27
- let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` :xAxisValue;
34
+ {(config.runtime.lineSeriesKeys || config.runtime.seriesKeys).map((seriesKey, index) => {
35
+ let lineType = config.series.filter(item => item.dataKey === seriesKey)[0].type
36
+ const seriesData = config.series.filter(item => item.dataKey === seriesKey)
37
+ const seriesAxis = seriesData[0].axis ? seriesData[0].axis : 'left'
38
+
39
+ return (
40
+ <Group
41
+ key={`series-${seriesKey}`}
42
+ opacity={config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(seriesKey) === -1 ? 0.5 : 1}
43
+ display={config.legend.behavior === 'highlight' || (seriesHighlight.length === 0 && !config.legend.dynamicLegend) || seriesHighlight.indexOf(seriesKey) !== -1 ? 'block' : 'none'}
44
+ >
45
+ {data.map((d, dataIndex) => {
46
+ let seriesAxis = config.series.filter(s => s.dataKey === seriesKey)[0].axis
47
+ const xAxisValue = config.runtime.xAxis.type === 'date' ? formatDate(parseDate(d[config.runtime.xAxis.dataKey])) : d[config.runtime.xAxis.dataKey]
48
+ const yAxisValue = formatNumber(getYAxisData(d, seriesKey));
49
+ let yAxisTooltip = config.runtime.yAxis.isLegendValue ? `${seriesKey}: ${yAxisValue} ` : config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue;
50
+ let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
51
+ if (seriesAxis === 'Left') {
52
+ yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${formatNumber(getYAxisData(d, seriesKey))}` : formatNumber(getYAxisData(d, seriesKey))
53
+ } else {
54
+ yAxisTooltip = config.runtime.yAxis.rightLabel ? `${config.runtime.yAxis.rightLabel}: ${formatNumber(getYAxisData(d, seriesKey))}` : formatNumber(getYAxisData(d, seriesKey))
55
+ }
56
+ const tooltip = `<div>
57
+ ${yAxisTooltip}<br />
58
+ ${xAxisTooltip}<br />
59
+ ${config.seriesLabel ? `${config.seriesLabel}: ${seriesKey}` : ''}
60
+ </div>`
61
+ let circleRadii = 4.5
62
+ return (
63
+ d[seriesKey] !== undefined &&
64
+ d[seriesKey] !== '' &&
65
+ d[seriesKey] !== null && (
66
+ <Group key={`series-${seriesKey}-point-${dataIndex}`}>
67
+ <Text
68
+ display={config.labels ? 'block' : 'none'}
69
+ x={xScale(getXAxisData(d))}
70
+ y={seriesAxis === 'Right' ? yScaleRight(getYAxisData(d, seriesKey)) : yScale(getYAxisData(d, seriesKey))}
71
+ fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
72
+ textAnchor='middle'
73
+ >
74
+ {formatNumber(d[seriesKey])}
75
+ </Text>
28
76
 
29
- const tooltip = `<div>
30
- ${yAxisTooltip}<br />
31
- ${xAxisTooltip}<br />
32
- ${config.seriesLabel ? `${config.seriesLabel}: ${seriesKey}` : ''}
33
- </div>`
77
+ <circle
78
+ key={`${seriesKey}-${dataIndex}`}
79
+ r={circleRadii}
80
+ cx={xScale(getXAxisData(d))}
81
+ cy={seriesAxis === 'Right' ? yScaleRight(getYAxisData(d, seriesKey)) : yScale(getYAxisData(d, seriesKey))}
82
+ fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
83
+ style={{ fill: colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000' }}
84
+ data-tip={tooltip}
85
+ data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
86
+ />
87
+ </Group>
88
+ )
89
+ )
90
+ })}
34
91
 
35
- let circleRadii = 4.5
92
+ <LinePath
93
+ curve={allCurves.curveLinear}
94
+ data={data}
95
+ x={d => xScale(getXAxisData(d))}
96
+ y={d => (seriesAxis === 'Right' ? yScaleRight(getYAxisData(d, seriesKey)) : yScale(getYAxisData(d, seriesKey)))}
97
+ stroke={
98
+ colorScale && !config.legend.dynamicLegend
99
+ ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey)
100
+ : // is dynamic legend
101
+ config.legend.dynamicLegend
102
+ ? colorPalettes[config.palette][index]
103
+ : // fallback
104
+ '#000'
105
+ }
106
+ strokeWidth={2}
107
+ strokeOpacity={1}
108
+ shapeRendering='geometricPrecision'
109
+ strokeDasharray={lineType ? handleLineType(lineType) : 0}
110
+ defined={(item,i) => {
111
+ return item[config.runtime.seriesLabels[seriesKey]] !== "" && item[config.runtime.seriesLabels[seriesKey]] !== null;
112
+ }}
113
+ />
114
+ </Group>
115
+ )
116
+ })}
36
117
 
37
- return (
38
- <Group key={`series-${seriesKey}-point-${dataIndex}`}>
39
- <Text
40
- display={config.labels ? 'block' : 'none'}
41
- x={xScale(getXAxisData(d))}
42
- y={yScale(getYAxisData(d, seriesKey))}
43
- fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
44
- textAnchor="middle">
45
- {formatNumber(d[seriesKey])}
46
- </Text>
47
- <circle
48
- key={`${seriesKey}-${dataIndex}`}
49
- r={circleRadii}
50
- cx={xScale(getXAxisData(d))}
51
- cy={yScale(getYAxisData(d, seriesKey))}
52
- fill={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
53
- style={{fill: colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}}
54
- data-tip={tooltip}
55
- data-for={`cdc-open-viz-tooltip-${config.runtime.uniqueId}`}
56
- />
57
- </Group>
58
- )
59
- })}
60
- <LinePath
61
- curve={allCurves.curveLinear}
62
- data={data}
63
- x={(d) => xScale(getXAxisData(d))}
64
- y={(d) => yScale(getYAxisData(d, seriesKey))}
65
- stroke={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
66
- strokeWidth={2}
67
- strokeOpacity={1}
68
- shapeRendering="geometricPrecision"
69
- />
70
- </Group>
71
- ))
72
- }
118
+ {/* Message when dynamic legend and nothing has been picked */}
119
+ {config.legend.dynamicLegend && seriesHighlight.length === 0 && (
120
+ <Text x={xMax / 2} y={yMax / 2} fill='black' textAnchor='middle' color='black'>
121
+ {config.legend.dynamicLegendChartMessage}
122
+ </Text>
123
+ )}
73
124
  </Group>
74
125
  </ErrorBoundary>
75
- );
126
+ )
76
127
  }