@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.
- package/dist/cdcchart.js +44197 -38258
- package/examples/cases-year.json +13379 -0
- package/examples/feature/annotations/index.json +542 -0
- package/examples/gallery/bar-chart-vertical/combo-line-chart.json +76 -15
- package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +5 -5
- package/examples/xaxis.json +493 -0
- package/index.html +20 -10
- package/package.json +5 -4
- package/src/CdcChart.tsx +462 -172
- package/src/_stories/Chart.Legend.Gradient.tsx +19 -0
- package/src/_stories/Chart.stories.tsx +18 -171
- package/src/_stories/ChartAnnotation.stories.tsx +32 -0
- package/src/_stories/_mock/annotation_category_mock.json +473 -0
- package/src/_stories/_mock/annotation_date-linear_mock.json +530 -0
- package/{examples/feature/line/line-chart.json → src/_stories/_mock/annotation_date-time_mock.json} +150 -69
- package/src/_stories/_mock/legend.gradient_mock.json +236 -0
- package/src/_stories/_mock/line_chart_two_points_new_chart.json +128 -0
- package/src/_stories/_mock/line_chart_two_points_regression_test.json +127 -0
- package/src/_stories/_mock/lollipop.json +171 -0
- package/src/components/Annotations/components/AnnotationDraggable.styles.css +31 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +207 -0
- package/src/components/Annotations/components/AnnotationDropdown.styles.css +14 -0
- package/src/components/Annotations/components/AnnotationDropdown.tsx +72 -0
- package/src/components/Annotations/components/AnnotationList.styles.css +45 -0
- package/src/components/Annotations/components/AnnotationList.tsx +42 -0
- package/src/components/Annotations/components/findNearestDatum.ts +138 -0
- package/src/components/Annotations/components/helpers/index.tsx +46 -0
- package/src/components/Annotations/index.tsx +13 -0
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +1 -1
- package/src/components/AreaChart/components/AreaChart.jsx +1 -1
- package/src/components/Axis/Categorical.Axis.tsx +145 -0
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +47 -44
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +0 -1
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +11 -14
- package/src/components/BarChart/components/BarChart.Vertical.tsx +67 -30
- package/src/components/BarChart/helpers/index.ts +91 -0
- package/src/components/BrushChart.tsx +205 -0
- package/src/components/EditorPanel/EditorPanel.tsx +1794 -403
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +320 -0
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +282 -18
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +43 -8
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -4
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +4 -13
- package/src/components/EditorPanel/components/Panels/index.tsx +3 -1
- package/src/components/EditorPanel/components/panels.scss +4 -0
- package/src/components/EditorPanel/editor-panel.scss +35 -3
- package/src/components/EditorPanel/{useEditorPermissions.js → useEditorPermissions.ts} +105 -17
- package/src/components/Legend/Legend.Component.tsx +185 -194
- package/src/components/Legend/Legend.Suppression.tsx +146 -0
- package/src/components/Legend/Legend.tsx +21 -5
- package/src/components/Legend/helpers/createFormatLabels.tsx +1 -1
- package/src/components/Legend/helpers/index.ts +35 -0
- package/src/components/LegendWrapper.tsx +26 -0
- package/src/components/LineChart/LineChartProps.ts +1 -15
- package/src/components/LineChart/components/LineChart.BumpCircle.tsx +103 -0
- package/src/components/LineChart/components/LineChart.Circle.tsx +47 -8
- package/src/components/LineChart/helpers.ts +72 -14
- package/src/components/LineChart/index.tsx +117 -42
- package/src/components/LinearChart.jsx +179 -136
- package/src/components/LinearChart.tsx +1366 -0
- package/src/components/PairedBarChart.jsx +9 -9
- package/src/components/PieChart/PieChart.tsx +75 -18
- package/src/components/Sankey/index.tsx +89 -30
- package/src/components/ScatterPlot/ScatterPlot.jsx +22 -8
- package/src/components/Sparkline/components/SparkLine.tsx +2 -2
- package/src/components/ZoomBrush.tsx +90 -44
- package/src/data/initial-state.js +25 -7
- package/src/helpers/handleChartTabbing.ts +8 -0
- package/src/helpers/isConvertLineToBarGraph.ts +4 -0
- package/src/hooks/{useBarChart.js → useBarChart.ts} +2 -40
- package/src/hooks/useColorScale.ts +1 -1
- package/src/hooks/useLegendClasses.ts +68 -0
- package/src/hooks/useMinMax.ts +12 -7
- package/src/hooks/useScales.ts +58 -26
- package/src/hooks/useTooltip.tsx +135 -25
- package/src/scss/DataTable.scss +2 -1
- package/src/scss/main.scss +128 -28
- package/src/types/ChartConfig.ts +83 -10
- package/src/types/ChartContext.ts +14 -4
- package/tests-examples/helpers/testZeroValue.test.ts +30 -0
- package/LICENSE +0 -201
- package/src/components/BrushHandle.jsx +0 -17
- package/src/components/LineChart/index.scss +0 -1
- package/src/helpers/filterData.ts +0 -18
- package/src/helpers/tests/computeMarginBottom.test.ts +0 -21
- package/src/hooks/useLegendClasses.js +0 -31
- /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 {
|
|
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 {
|
|
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 (
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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') &&
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
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>
|
|
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
|
-
{
|
|
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>
|
|
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>
|
|
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
|
)
|