@cdc/chart 4.24.5 → 4.24.9

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 (87) hide show
  1. package/dist/cdcchart.js +44197 -38258
  2. package/examples/cases-year.json +13379 -0
  3. package/examples/feature/annotations/index.json +542 -0
  4. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +76 -15
  5. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +5 -5
  6. package/examples/xaxis.json +493 -0
  7. package/index.html +20 -10
  8. package/package.json +5 -4
  9. package/src/CdcChart.tsx +462 -172
  10. package/src/_stories/Chart.Legend.Gradient.tsx +19 -0
  11. package/src/_stories/Chart.stories.tsx +18 -171
  12. package/src/_stories/ChartAnnotation.stories.tsx +32 -0
  13. package/src/_stories/_mock/annotation_category_mock.json +473 -0
  14. package/src/_stories/_mock/annotation_date-linear_mock.json +530 -0
  15. package/{examples/feature/line/line-chart.json → src/_stories/_mock/annotation_date-time_mock.json} +150 -69
  16. package/src/_stories/_mock/legend.gradient_mock.json +236 -0
  17. package/src/_stories/_mock/line_chart_two_points_new_chart.json +128 -0
  18. package/src/_stories/_mock/line_chart_two_points_regression_test.json +127 -0
  19. package/src/_stories/_mock/lollipop.json +171 -0
  20. package/src/components/Annotations/components/AnnotationDraggable.styles.css +31 -0
  21. package/src/components/Annotations/components/AnnotationDraggable.tsx +207 -0
  22. package/src/components/Annotations/components/AnnotationDropdown.styles.css +14 -0
  23. package/src/components/Annotations/components/AnnotationDropdown.tsx +72 -0
  24. package/src/components/Annotations/components/AnnotationList.styles.css +45 -0
  25. package/src/components/Annotations/components/AnnotationList.tsx +42 -0
  26. package/src/components/Annotations/components/findNearestDatum.ts +138 -0
  27. package/src/components/Annotations/components/helpers/index.tsx +46 -0
  28. package/src/components/Annotations/index.tsx +13 -0
  29. package/src/components/AreaChart/components/AreaChart.Stacked.jsx +1 -1
  30. package/src/components/AreaChart/components/AreaChart.jsx +1 -1
  31. package/src/components/Axis/Categorical.Axis.tsx +145 -0
  32. package/src/components/BarChart/components/BarChart.Horizontal.tsx +47 -44
  33. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +0 -1
  34. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +11 -14
  35. package/src/components/BarChart/components/BarChart.Vertical.tsx +67 -30
  36. package/src/components/BarChart/helpers/index.ts +91 -0
  37. package/src/components/BrushChart.tsx +205 -0
  38. package/src/components/EditorPanel/EditorPanel.tsx +1794 -403
  39. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +320 -0
  40. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +282 -18
  41. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +43 -8
  42. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -4
  43. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +4 -13
  44. package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
  45. package/src/components/EditorPanel/components/panels.scss +4 -0
  46. package/src/components/EditorPanel/editor-panel.scss +35 -3
  47. package/src/components/EditorPanel/{useEditorPermissions.js → useEditorPermissions.ts} +105 -17
  48. package/src/components/Legend/Legend.Component.tsx +185 -194
  49. package/src/components/Legend/Legend.Suppression.tsx +146 -0
  50. package/src/components/Legend/Legend.tsx +21 -5
  51. package/src/components/Legend/helpers/createFormatLabels.tsx +1 -1
  52. package/src/components/Legend/helpers/index.ts +35 -0
  53. package/src/components/LegendWrapper.tsx +26 -0
  54. package/src/components/LineChart/LineChartProps.ts +1 -15
  55. package/src/components/LineChart/components/LineChart.BumpCircle.tsx +103 -0
  56. package/src/components/LineChart/components/LineChart.Circle.tsx +47 -8
  57. package/src/components/LineChart/helpers.ts +72 -14
  58. package/src/components/LineChart/index.tsx +117 -42
  59. package/src/components/LinearChart.jsx +179 -136
  60. package/src/components/LinearChart.tsx +1366 -0
  61. package/src/components/PairedBarChart.jsx +9 -9
  62. package/src/components/PieChart/PieChart.tsx +75 -18
  63. package/src/components/Sankey/index.tsx +89 -30
  64. package/src/components/ScatterPlot/ScatterPlot.jsx +22 -8
  65. package/src/components/Sparkline/components/SparkLine.tsx +2 -2
  66. package/src/components/ZoomBrush.tsx +90 -44
  67. package/src/data/initial-state.js +25 -7
  68. package/src/helpers/handleChartTabbing.ts +8 -0
  69. package/src/helpers/isConvertLineToBarGraph.ts +4 -0
  70. package/src/hooks/{useBarChart.js → useBarChart.ts} +2 -40
  71. package/src/hooks/useColorScale.ts +1 -1
  72. package/src/hooks/useLegendClasses.ts +68 -0
  73. package/src/hooks/useMinMax.ts +12 -7
  74. package/src/hooks/useScales.ts +58 -26
  75. package/src/hooks/useTooltip.tsx +135 -25
  76. package/src/scss/DataTable.scss +2 -1
  77. package/src/scss/main.scss +128 -28
  78. package/src/types/ChartConfig.ts +83 -10
  79. package/src/types/ChartContext.ts +14 -4
  80. package/tests-examples/helpers/testZeroValue.test.ts +30 -0
  81. package/LICENSE +0 -201
  82. package/src/components/BrushHandle.jsx +0 -17
  83. package/src/components/LineChart/index.scss +0 -1
  84. package/src/helpers/filterData.ts +0 -18
  85. package/src/helpers/tests/computeMarginBottom.test.ts +0 -21
  86. package/src/hooks/useLegendClasses.js +0 -31
  87. /package/src/hooks/{useReduceData.js → useReduceData.ts} +0 -0
@@ -0,0 +1,320 @@
1
+ import React, { useContext } from 'react'
2
+ import ConfigContext from '../../../../ConfigContext.js'
3
+
4
+ // CDC Core
5
+ import Accordion from '@cdc/core/components/ui/Accordion'
6
+ import Button from '@cdc/core/components/elements/Button'
7
+ import _ from 'lodash'
8
+
9
+ // types
10
+ import { type PanelProps } from './../PanelProps'
11
+ // styles
12
+ import './../panels.scss'
13
+
14
+ const PanelAnnotate: React.FC<PanelProps> = props => {
15
+ const { updateConfig, config, unfilteredData, dimensions, isDraggingAnnotation } = useContext(ConfigContext)
16
+
17
+ const getColumns = (filter = true) => {
18
+ const columns = {}
19
+ unfilteredData.forEach(row => {
20
+ Object.keys(row).forEach(columnName => (columns[columnName] = true))
21
+ })
22
+
23
+ if (filter) {
24
+ Object.keys(columns).forEach(key => {
25
+ if (
26
+ (config.series && config.series.filter(series => series.dataKey === key).length > 0) ||
27
+ (config.confidenceKeys && Object.keys(config.confidenceKeys).includes(key))
28
+ ) {
29
+ delete columns[key]
30
+ }
31
+ })
32
+ }
33
+
34
+ return Object.keys(columns)
35
+ }
36
+
37
+ const handleAnnotationUpdate = (value, property, index) => {
38
+ const svgContainer = document.querySelector('.chart-container > div > svg')?.getBoundingClientRect()
39
+ const newSvgDims = [svgContainer.width, svgContainer.height]
40
+ const annotations = [...config?.annotations]
41
+ annotations[index][property] = value
42
+ annotations[index].savedDimensions = newSvgDims
43
+
44
+ updateConfig({
45
+ ...config,
46
+ annotations
47
+ })
48
+ }
49
+
50
+ const handleAddAnnotation = () => {
51
+ const svgContainer = document.querySelector('.chart-container svg')?.getBoundingClientRect()
52
+ const newSvgDims = [svgContainer.width, svgContainer.height]
53
+
54
+ const newAnnotation = {
55
+ text: 'New Annotation',
56
+ snapToNearestPoint: false,
57
+ fontSize: 16,
58
+ bezier: 10,
59
+ show: {
60
+ desktop: true,
61
+ tablet: true,
62
+ mobile: true
63
+ },
64
+ connectorType: 'line',
65
+ colors: {
66
+ label: 'black',
67
+ connector: 'black',
68
+ marker: 'black'
69
+ },
70
+ selected: true,
71
+ anchor: {
72
+ vertical: false,
73
+ horizontal: false
74
+ },
75
+ marker: 'arrow',
76
+ edit: {
77
+ subject: true,
78
+ label: true
79
+ },
80
+ seriesKey: '',
81
+ x: 50,
82
+ y: Number(newSvgDims?.[1] / 2),
83
+ xKey:
84
+ config.xAxis.type === 'date'
85
+ ? new Date(config?.data?.[0]?.[config.xAxis.dataKey]).getTime()
86
+ : config.xAxis.type === 'categorical'
87
+ ? '1/15/2016'
88
+ : '',
89
+ yKey: '',
90
+ dx: 20,
91
+ dy: -20,
92
+ opacity: '100',
93
+ savedDimensions: newSvgDims,
94
+ connectionType: 'line'
95
+ }
96
+
97
+ const annotations = Array.isArray(config.annotations) ? config.annotations : []
98
+
99
+ updateConfig({
100
+ ...config,
101
+ annotations: [...annotations, newAnnotation]
102
+ })
103
+ }
104
+
105
+ const handleRemoveAnnotation = (annotationIndex: number) => {
106
+ const updated = config.annotations.filter((_, index) => index !== annotationIndex)
107
+ updateConfig({
108
+ ...config,
109
+ annotations: updated
110
+ })
111
+ }
112
+
113
+ return (
114
+ <Accordion key={props.name}>
115
+ <Accordion.Section title={props.name} key={props.name}>
116
+ <label key={`key-1`}>
117
+ Show Annotation Dropdown
118
+ <input
119
+ type='checkbox'
120
+ checked={config?.general?.showAnnotationDropdown || false}
121
+ onChange={e => {
122
+ updateConfig({
123
+ ...config,
124
+ general: {
125
+ ...config.general,
126
+ showAnnotationDropdown: e.target.checked
127
+ }
128
+ })
129
+ }}
130
+ />
131
+ </label>
132
+
133
+ {config.general.showAnnotationDropdown && (
134
+ <label key={`key-2`}>
135
+ Annotation Dropdown Title:
136
+ <input
137
+ type='text'
138
+ style={{ marginBottom: '10px' }}
139
+ value={config?.general?.annotationDropdownText}
140
+ onChange={e => {
141
+ updateConfig({
142
+ ...config,
143
+ general: {
144
+ ...config.general,
145
+ annotationDropdownText: e.target.value
146
+ }
147
+ })
148
+ }}
149
+ />
150
+ </label>
151
+ )}
152
+ {config?.annotations &&
153
+ config?.annotations.map((annotation, index) => (
154
+ <Accordion key={index}>
155
+ <Accordion.Section
156
+ title={annotation.text ? annotation.text.substring(0, 15) + '...' : `Annotation ${index + 1}`}
157
+ >
158
+ <div className='annotation-group'>
159
+ <label>
160
+ Annotation Text:
161
+ <textarea
162
+ rows={5}
163
+ value={annotation.text}
164
+ onChange={e => handleAnnotationUpdate(e.target.value, 'text', index)}
165
+ />
166
+ </label>
167
+ <label>
168
+ Opacity
169
+ <br />
170
+ <input
171
+ type='range'
172
+ onChange={e => {
173
+ const updatedAnnotations = _.cloneDeep(config?.annotations)
174
+ updatedAnnotations[index].opacity = e.target.value
175
+ updateConfig({
176
+ ...config,
177
+ annotations: updatedAnnotations
178
+ })
179
+ }}
180
+ value={config?.annotations?.[index]?.opacity || '100'}
181
+ />
182
+ </label>
183
+
184
+ <label>
185
+ Edit Subject
186
+ <input
187
+ type='checkbox'
188
+ checked={config?.annotations[index]?.edit?.subject || false}
189
+ onChange={e => {
190
+ const updatedAnnotations = _.cloneDeep(config?.annotations)
191
+ updatedAnnotations[index].edit.subject = e.target.checked
192
+ updateConfig({
193
+ ...config,
194
+ annotations: updatedAnnotations
195
+ })
196
+ }}
197
+ />
198
+ </label>
199
+ <label>
200
+ Edit Label
201
+ <input
202
+ type='checkbox'
203
+ checked={config?.annotations[index]?.edit?.label || false}
204
+ onChange={e => {
205
+ const updatedAnnotations = _.cloneDeep(config?.annotations)
206
+ updatedAnnotations[index].edit.label = e.target.checked
207
+ updateConfig({
208
+ ...config,
209
+ annotations: updatedAnnotations
210
+ })
211
+ }}
212
+ />
213
+ </label>
214
+
215
+ <label>
216
+ Connection Type:
217
+ <select
218
+ key='annotation-connection-type'
219
+ onChange={e => {
220
+ const updatedAnnotations = _.cloneDeep(config?.annotations)
221
+ updatedAnnotations[index].connectionType = e.target.value
222
+ updateConfig({
223
+ ...config,
224
+ annotations: updatedAnnotations
225
+ })
226
+ }}
227
+ value={config?.annotations[index]?.connectionType}
228
+ >
229
+ <option key='select' value='select'>
230
+ Select
231
+ </option>
232
+ {['curve', 'line', 'elbow', 'none'].map((side, index) => (
233
+ <option key={side} value={side}>
234
+ {side}
235
+ </option>
236
+ ))}
237
+ </select>
238
+ </label>
239
+
240
+ {annotation.connectionType === 'curve' && (
241
+ <>
242
+ <label>
243
+ Curve Control
244
+ {/* create a range input */}
245
+ <input
246
+ type='range'
247
+ min='-20'
248
+ max='20'
249
+ value={config?.annotations[index]?.bezier || 0}
250
+ onChange={e => {
251
+ const updatedAnnotations = _.cloneDeep(config?.annotations)
252
+ updatedAnnotations[index].bezier = e.target.value
253
+ updateConfig({
254
+ ...config,
255
+ annotations: updatedAnnotations
256
+ })
257
+ }}
258
+ />
259
+ </label>
260
+ </>
261
+ )}
262
+
263
+ {/* <label>
264
+ Connection Location:
265
+ <select
266
+ onChange={e => {
267
+ const updatedAnnotations = _.cloneDeep(config?.annotations)
268
+ updatedAnnotations[index].connectionLocation = e.target.value
269
+ updateConfig({
270
+ ...config,
271
+ annotations: updatedAnnotations
272
+ })
273
+ }}
274
+ >
275
+ {['auto', 'left', 'top', 'bottom', 'right'].map((side, index) => (
276
+ <option key={side} value={side}>
277
+ {side}
278
+ </option>
279
+ ))}
280
+ </select>
281
+ </label> */}
282
+
283
+ <label>
284
+ Marker
285
+ <select
286
+ key='annotation-marker'
287
+ value={annotation.marker}
288
+ onChange={e => {
289
+ const updatedAnnotations = _.cloneDeep(config?.annotations)
290
+ updatedAnnotations[index].marker = e.target.value
291
+ updateConfig({
292
+ ...config,
293
+ annotations: updatedAnnotations
294
+ })
295
+ }}
296
+ >
297
+ {['arrow', 'circle'].map((column, columnIndex) => {
298
+ return <option key={`col-${columnIndex}`}>{column}</option>
299
+ })}
300
+ </select>
301
+ </label>
302
+
303
+ <Button className='warn btn-warn btn btn-remove delete' onClick={() => handleRemoveAnnotation(index)}>
304
+ Delete Annotation
305
+ </Button>
306
+ </div>
307
+ </Accordion.Section>
308
+ </Accordion>
309
+ ))}
310
+ {config?.annotations?.length < 3 && (
311
+ <Button onClick={handleAddAnnotation} className='mt-2'>
312
+ Add Annotation
313
+ </Button>
314
+ )}
315
+ </Accordion.Section>
316
+ </Accordion>
317
+ )
318
+ }
319
+
320
+ export default PanelAnnotate
@@ -1,7 +1,12 @@
1
1
  import { useContext, FC } from 'react'
2
2
 
3
3
  // external libraries
4
- import { AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
4
+ import {
5
+ AccordionItem,
6
+ AccordionItemHeading,
7
+ AccordionItemPanel,
8
+ AccordionItemButton
9
+ } from 'react-accessible-accordion'
5
10
  import { approvedCurveTypes } from '@cdc/core/helpers/lineChartHelpers'
6
11
 
7
12
  // core
@@ -18,11 +23,24 @@ import { PanelProps } from '../PanelProps'
18
23
  const PanelGeneral: FC<PanelProps> = props => {
19
24
  const { config } = useContext(ConfigContext)
20
25
  const { updateField } = useEditorPanelContext()
21
- const { enabledChartTypes, visHasNumbersOnBars, visHasLabelOnData, visSupportsChartHeight, visSupportsSuperTitle, visSupportsFootnotes } = useEditorPermissions()
26
+ const {
27
+ enabledChartTypes,
28
+ visHasNumbersOnBars,
29
+ visHasaAdditionalLabelsOnBars,
30
+ visHasLabelOnData,
31
+ visSupportsChartHeight,
32
+ visSupportsMobileChartHeight,
33
+ visSupportsSuperTitle,
34
+ visSupportsFootnotes
35
+ } = useEditorPermissions()
22
36
  const { visualizationType, visualizationSubType, barStyle } = config
23
37
 
24
38
  const showBarStyleOptions = () => {
25
- if ((visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && visualizationSubType !== 'stacked' && (config.orientation === 'horizontal' || config.orientation === 'vertical')) {
39
+ if (
40
+ (visualizationType === 'Bar' || visualizationType === 'Deviation Bar') &&
41
+ visualizationSubType !== 'stacked' &&
42
+ (config.orientation === 'horizontal' || config.orientation === 'vertical')
43
+ ) {
26
44
  return ['flat', 'rounded', 'lollipop']
27
45
  } else {
28
46
  return ['flat', 'rounded']
@@ -37,17 +55,147 @@ const PanelGeneral: FC<PanelProps> = props => {
37
55
  <AccordionItemButton>General</AccordionItemButton>
38
56
  </AccordionItemHeading>
39
57
  <AccordionItemPanel>
40
- <Select value={visualizationType} fieldName='visualizationType' label='Chart Type' updateField={updateField} options={enabledChartTypes} />
41
- {(visualizationType === 'Bar' || visualizationType === 'Combo' || visualizationType === 'Area Chart') && <Select value={visualizationSubType || 'Regular'} fieldName='visualizationSubType' label='Chart Subtype' updateField={updateField} options={['regular', 'stacked']} />}
42
- {visualizationType === 'Area Chart' && visualizationSubType === 'stacked' && <Select value={config.stackedAreaChartLineType || 'Linear'} fieldName='stackedAreaChartLineType' label='Stacked Area Chart Line Type' updateField={updateField} options={Object.keys(approvedCurveTypes)} />}
43
- {visualizationType === 'Bar' && <Select value={config.orientation || 'vertical'} fieldName='orientation' label='Orientation' updateField={updateField} options={['vertical', 'horizontal']} />}
58
+ {config?.visualizationType !== 'Sankey' && (
59
+ <Select
60
+ value={visualizationType}
61
+ fieldName='visualizationType'
62
+ label='Chart Type'
63
+ updateField={updateField}
64
+ options={enabledChartTypes}
65
+ />
66
+ )}
67
+ {visSupportsChartHeight() && config.orientation === 'vertical' && (
68
+ <div className={visSupportsMobileChartHeight() ? 'two-col-inputs' : ''}>
69
+ <TextField
70
+ type='number'
71
+ value={config.heights.vertical}
72
+ section='heights'
73
+ fieldName='vertical'
74
+ label='Chart Height'
75
+ updateField={updateField}
76
+ tooltip={
77
+ <Tooltip style={{ textTransform: 'none' }}>
78
+ <Tooltip.Target>
79
+ ˝
80
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
81
+ </Tooltip.Target>
82
+ <Tooltip.Content>
83
+ <p>
84
+ For some visualization types, such as the Sankey diagram, it may be necessary to adjust the chart
85
+ height for optimal display.
86
+ </p>
87
+ </Tooltip.Content>
88
+ </Tooltip>
89
+ }
90
+ />
91
+ {visSupportsMobileChartHeight() && config.orientation === 'vertical' && (
92
+ <TextField
93
+ type='number'
94
+ value={config.heights.mobileVertical}
95
+ section='heights'
96
+ fieldName='mobileVertical'
97
+ label='Mobile Height'
98
+ updateField={updateField}
99
+ tooltip={
100
+ <Tooltip style={{ textTransform: 'none' }}>
101
+ <Tooltip.Target>
102
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
103
+ </Tooltip.Target>
104
+ <Tooltip.Content>
105
+ <p>
106
+ If the chart height is not optimized for mobile, you can adjust the height for better display.
107
+ Not setting a value will default to the chart height.
108
+ </p>
109
+ </Tooltip.Content>
110
+ </Tooltip>
111
+ }
112
+ />
113
+ )}
114
+ </div>
115
+ )}
116
+ {(visualizationType === 'Bar' || visualizationType === 'Combo' || visualizationType === 'Area Chart') && (
117
+ <Select
118
+ value={visualizationSubType || 'Regular'}
119
+ fieldName='visualizationSubType'
120
+ label='Chart Subtype'
121
+ updateField={updateField}
122
+ options={['regular', 'stacked']}
123
+ />
124
+ )}
125
+ {visualizationType === 'Area Chart' && visualizationSubType === 'stacked' && (
126
+ <Select
127
+ value={config.stackedAreaChartLineType || 'Linear'}
128
+ fieldName='stackedAreaChartLineType'
129
+ label='Stacked Area Chart Line Type'
130
+ updateField={updateField}
131
+ options={Object.keys(approvedCurveTypes)}
132
+ />
133
+ )}
134
+ {visualizationType === 'Bar' && (
135
+ <Select
136
+ value={config.orientation || 'vertical'}
137
+ fieldName='orientation'
138
+ label='Orientation'
139
+ updateField={updateField}
140
+ options={['vertical', 'horizontal']}
141
+ />
142
+ )}
44
143
  {visualizationType === 'Deviation Bar' && <Select label='Orientation' options={['horizontal']} />}
45
- {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && <Select value={config.isLollipopChart ? 'lollipop' : barStyle || 'flat'} fieldName='barStyle' label='bar style' updateField={updateField} options={showBarStyleOptions()} />}
46
- {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && barStyle === 'rounded' && <Select value={config.tipRounding || 'top'} fieldName='tipRounding' label='tip rounding' updateField={updateField} options={['top', 'full']} />}
47
- {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && barStyle === 'rounded' && <Select value={config.roundingStyle || 'standard'} fieldName='roundingStyle' label='rounding style' updateField={updateField} options={['standard', 'shallow', 'finger']} />}
48
- {visualizationType === 'Bar' && config.orientation === 'horizontal' && <Select value={config.yAxis.labelPlacement || 'Below Bar'} section='yAxis' fieldName='labelPlacement' label='Label Placement' updateField={updateField} options={['Below Bar', 'On Date/Category Axis']} />}
144
+ {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && (
145
+ <Select
146
+ value={config.isLollipopChart ? 'lollipop' : barStyle || 'flat'}
147
+ fieldName='barStyle'
148
+ label='bar style'
149
+ updateField={updateField}
150
+ options={showBarStyleOptions()}
151
+ tooltip={
152
+ <Tooltip style={{ textTransform: 'none' }}>
153
+ <Tooltip.Target>
154
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
155
+ </Tooltip.Target>
156
+ <Tooltip.Content>
157
+ <p>Consider using the 'Flat' bar style when presenting data that includes '0' values.</p>
158
+ </Tooltip.Content>
159
+ </Tooltip>
160
+ }
161
+ />
162
+ )}
163
+ {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && barStyle === 'rounded' && (
164
+ <Select
165
+ value={config.tipRounding || 'top'}
166
+ fieldName='tipRounding'
167
+ label='tip rounding'
168
+ updateField={updateField}
169
+ options={['top', 'full']}
170
+ />
171
+ )}
172
+ {(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && barStyle === 'rounded' && (
173
+ <Select
174
+ value={config.roundingStyle || 'standard'}
175
+ fieldName='roundingStyle'
176
+ label='rounding style'
177
+ updateField={updateField}
178
+ options={['standard', 'shallow', 'finger']}
179
+ />
180
+ )}
181
+ {visualizationType === 'Bar' && config.orientation === 'horizontal' && (
182
+ <Select
183
+ value={config.yAxis.labelPlacement || 'Below Bar'}
184
+ section='yAxis'
185
+ fieldName='labelPlacement'
186
+ label='Label Placement'
187
+ updateField={updateField}
188
+ options={['Below Bar', 'On Date/Category Axis']}
189
+ />
190
+ )}
49
191
  {visHasNumbersOnBars() ? (
50
- <CheckBox value={config.yAxis.displayNumbersOnBar} section='yAxis' fieldName='displayNumbersOnBar' label={config.isLollipopChart ? 'Display Numbers after Bar' : 'Display Numbers on Bar'} updateField={updateField} />
192
+ <CheckBox
193
+ value={config.yAxis.displayNumbersOnBar}
194
+ section='yAxis'
195
+ fieldName='displayNumbersOnBar'
196
+ label={config.isLollipopChart ? 'Display Numbers after Bar' : 'Display Numbers on Bar'}
197
+ updateField={updateField}
198
+ />
51
199
  ) : (
52
200
  visHasLabelOnData() && (
53
201
  <CheckBox
@@ -61,14 +209,126 @@ const PanelGeneral: FC<PanelProps> = props => {
61
209
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
62
210
  </Tooltip.Target>
63
211
  <Tooltip.Content>
64
- <p>Selecting this option will not hide the display of "zero value", "suppressed data", or "no data" indicators on the chart (if applicable).</p>
212
+ <p>
213
+ Selecting this option will <i> not </i> hide the display of "zero value", "suppressed data", or
214
+ "missing data" indicators on the chart (if applicable).
215
+ </p>
65
216
  </Tooltip.Content>
66
217
  </Tooltip>
67
218
  }
68
219
  />
69
220
  )
70
221
  )}
71
- {visualizationType === 'Pie' && <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />}
222
+ {visHasaAdditionalLabelsOnBars() && (
223
+ <>
224
+ <CheckBox
225
+ tooltip={
226
+ <Tooltip style={{ textTransform: 'none' }}>
227
+ <Tooltip.Target>
228
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
229
+ </Tooltip.Target>
230
+ <Tooltip.Content>
231
+ {config.visualizationSubType === 'stacked' && (
232
+ <p>
233
+ We do not recommend using stacked vertical/horizontal bar charts for missing data. If you choose
234
+ to proceed, selecting this option will display 'N/A' in the tooltip hover and data table (e.g.
235
+ nothing will display in chart).
236
+ </p>
237
+ )}
238
+ {config.visualizationSubType !== 'stacked' && (
239
+ <p>
240
+ Selecting this option will display 'N/A' on the Date/Category Axis, in the tooltip hover, and in
241
+ the data table to indicate missing or undefined data values.
242
+ </p>
243
+ )}
244
+ </Tooltip.Content>
245
+ </Tooltip>
246
+ }
247
+ value={config.general.showMissingDataLabel}
248
+ section='general'
249
+ fieldName='showMissingDataLabel'
250
+ label='Display "Missing Data" Label'
251
+ updateField={updateField}
252
+ />
253
+ <CheckBox
254
+ display={
255
+ config.visualizationSubType === 'stacked' &&
256
+ (config.visualizationType === 'Bar' || config.visualizationType === 'Combo')
257
+ }
258
+ tooltip={
259
+ <Tooltip style={{ textTransform: 'none' }}>
260
+ <Tooltip.Target>
261
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
262
+ </Tooltip.Target>
263
+ <Tooltip.Content>
264
+ <p>
265
+ Selecting 'Remove Null Values' will hide the 'N/A' (no data indicator) when you hover over the
266
+ chart.
267
+ </p>
268
+ </Tooltip.Content>
269
+ </Tooltip>
270
+ }
271
+ value={config.general.hideNullValue}
272
+ section='general'
273
+ fieldName='hideNullValue'
274
+ label={`Remove "Null" Values From Hover`}
275
+ updateField={updateField}
276
+ />
277
+
278
+ <CheckBox
279
+ tooltip={
280
+ <Tooltip style={{ textTransform: 'none' }}>
281
+ <Tooltip.Target>
282
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
283
+ </Tooltip.Target>
284
+ <Tooltip.Content>
285
+ {config.visualizationSubType !== 'stacked' && (
286
+ <p>
287
+ Selecting this option will show the <i>suppression indicator </i> on the Date/Category axis,
288
+ within tooltips, and in the data table where suppressed data values appear in the Data Series.
289
+ </p>
290
+ )}
291
+
292
+ {config.visualizationSubType === 'stacked' && (
293
+ <p>
294
+ We do not recommend using stacked vertical/horizontal bar charts for suppressed data. If you
295
+ choose to proceed, selecting this option will display the 'suppressed data symbol' in the
296
+ tooltip hover and data table (e.g., nothing will display in the chart).
297
+ </p>
298
+ )}
299
+ </Tooltip.Content>
300
+ </Tooltip>
301
+ }
302
+ value={config.general.showSuppressedSymbol}
303
+ section='general'
304
+ fieldName='showSuppressedSymbol'
305
+ label='Display "suppressed data" label'
306
+ updateField={updateField}
307
+ />
308
+ </>
309
+ )}
310
+
311
+ {visualizationType === 'Pie' && (
312
+ <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />
313
+ )}
314
+ {visualizationType === 'Line' && (
315
+ <CheckBox
316
+ value={config.allowLineToBarGraph}
317
+ fieldName='allowLineToBarGraph'
318
+ label='Convert to Bar Graph'
319
+ updateField={updateField}
320
+ tooltip={
321
+ <Tooltip style={{ textTransform: 'none' }}>
322
+ <Tooltip.Target>
323
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
324
+ </Tooltip.Target>
325
+ <Tooltip.Content>
326
+ <p>Switch to bar graph when less than 3 data points available.</p>
327
+ </Tooltip.Content>
328
+ </Tooltip>
329
+ }
330
+ />
331
+ )}
72
332
 
73
333
  <TextField
74
334
  value={config.title || 'Chart Title'}
@@ -142,7 +402,10 @@ const PanelGeneral: FC<PanelProps> = props => {
142
402
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
143
403
  </Tooltip.Target>
144
404
  <Tooltip.Content>
145
- <p>Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
405
+ <p>
406
+ Enter supporting text to display below the data visualization, if applicable. The following HTML tags
407
+ are supported: strong, em, sup, and sub.
408
+ </p>
146
409
  </Tooltip.Content>
147
410
  </Tooltip>
148
411
  }
@@ -161,14 +424,15 @@ const PanelGeneral: FC<PanelProps> = props => {
161
424
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
162
425
  </Tooltip.Target>
163
426
  <Tooltip.Content>
164
- <p>Consider adding footnotes when displaying 'suppressed,' 'no data,' and 'zero values' to ensure accurate interpretation of the data.</p>
427
+ <p>
428
+ Consider adding footnotes when displaying 'suppressed,' 'no data,' and 'zero values' to ensure
429
+ accurate interpretation of the data.
430
+ </p>
165
431
  </Tooltip.Content>
166
432
  </Tooltip>
167
433
  }
168
434
  />
169
435
  )}
170
-
171
- {visSupportsChartHeight() && config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
172
436
  </AccordionItemPanel>
173
437
  </AccordionItem>
174
438
  )