@cdc/chart 4.24.4 → 4.24.7
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 +39611 -36038
- package/examples/feature/annotations/index.json +542 -0
- package/examples/xaxis.json +493 -0
- package/index.html +9 -8
- package/package.json +5 -4
- package/src/CdcChart.tsx +115 -71
- package/src/_stories/Chart.stories.tsx +26 -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/src/_stories/_mock/annotation_date-time_mock.json +530 -0
- package/src/_stories/_mock/bar-chart-suppressed.json +474 -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 +154 -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 +2 -2
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +78 -71
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +1 -2
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +11 -11
- package/src/components/BarChart/components/BarChart.Vertical.tsx +100 -87
- package/src/components/BarChart/helpers/index.ts +102 -0
- package/src/components/DeviationBar.jsx +4 -2
- package/src/components/EditorPanel/EditorPanel.tsx +435 -613
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +306 -0
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +135 -7
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +2 -3
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -5
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +3 -2
- 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 +19 -0
- package/src/components/EditorPanel/useEditorPermissions.js +23 -3
- package/src/components/Legend/Legend.Component.tsx +66 -15
- package/src/components/Legend/helpers/createFormatLabels.tsx +1 -1
- package/src/components/Legend/helpers/index.ts +5 -0
- package/src/components/LineChart/LineChartProps.ts +16 -6
- package/src/components/LineChart/components/LineChart.Circle.tsx +22 -11
- package/src/components/LineChart/helpers.ts +148 -10
- package/src/components/LineChart/index.tsx +71 -44
- package/src/components/LinearChart.jsx +184 -125
- package/src/components/PairedBarChart.jsx +9 -9
- package/src/components/PieChart/PieChart.tsx +4 -4
- package/src/components/Sankey/index.tsx +73 -20
- package/src/components/ScatterPlot/ScatterPlot.jsx +22 -8
- package/src/components/ZoomBrush.tsx +120 -55
- package/src/data/initial-state.js +14 -6
- package/src/helpers/handleChartTabbing.ts +8 -0
- package/src/helpers/isConvertLineToBarGraph.ts +4 -0
- package/src/hooks/{useBarChart.js → useBarChart.ts} +9 -22
- package/src/hooks/useColorScale.ts +1 -1
- package/src/hooks/useMinMax.ts +29 -5
- package/src/hooks/useScales.ts +48 -26
- package/src/hooks/useTooltip.tsx +62 -15
- package/src/scss/main.scss +69 -12
- package/src/types/ChartConfig.ts +53 -16
- package/src/types/ChartContext.ts +13 -0
- package/tests-examples/helpers/testZeroValue.test.ts +30 -0
- package/LICENSE +0 -201
- package/src/_stories/ChartLine.preliminary.tsx +0 -19
- package/src/_stories/ChartSuppress.stories.tsx +0 -19
- package/src/_stories/_mock/suppress_mock.json +0 -911
- package/src/helpers/computeMarginBottom.ts +0 -56
- package/src/helpers/filterData.ts +0 -18
- package/src/helpers/tests/computeMarginBottom.test.ts +0 -21
- /package/src/hooks/{useLegendClasses.js → useLegendClasses.ts} +0 -0
- /package/src/hooks/{useReduceData.js → useReduceData.ts} +0 -0
|
@@ -0,0 +1,306 @@
|
|
|
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 ((config.series && config.series.filter(series => series.dataKey === key).length > 0) || (config.confidenceKeys && Object.keys(config.confidenceKeys).includes(key))) {
|
|
26
|
+
delete columns[key]
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return Object.keys(columns)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const handleAnnotationUpdate = (value, property, index) => {
|
|
35
|
+
const svgContainer = document.querySelector('.chart-container > div > svg')?.getBoundingClientRect()
|
|
36
|
+
const newSvgDims = [svgContainer.width, svgContainer.height]
|
|
37
|
+
const annotations = [...config?.annotations]
|
|
38
|
+
annotations[index][property] = value
|
|
39
|
+
annotations[index].savedDimensions = newSvgDims
|
|
40
|
+
|
|
41
|
+
updateConfig({
|
|
42
|
+
...config,
|
|
43
|
+
annotations
|
|
44
|
+
})
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const handleAddAnnotation = () => {
|
|
48
|
+
const svgContainer = document.querySelector('.chart-container > div > svg')?.getBoundingClientRect()
|
|
49
|
+
const newSvgDims = [svgContainer.width, svgContainer.height]
|
|
50
|
+
|
|
51
|
+
const newAnnotation = {
|
|
52
|
+
text: 'New Annotation',
|
|
53
|
+
snapToNearestPoint: false,
|
|
54
|
+
fontSize: 16,
|
|
55
|
+
bezier: 10,
|
|
56
|
+
show: {
|
|
57
|
+
desktop: true,
|
|
58
|
+
tablet: true,
|
|
59
|
+
mobile: true
|
|
60
|
+
},
|
|
61
|
+
connectorType: 'line',
|
|
62
|
+
colors: {
|
|
63
|
+
label: 'black',
|
|
64
|
+
connector: 'black',
|
|
65
|
+
marker: 'black'
|
|
66
|
+
},
|
|
67
|
+
selected: true,
|
|
68
|
+
anchor: {
|
|
69
|
+
vertical: false,
|
|
70
|
+
horizontal: false
|
|
71
|
+
},
|
|
72
|
+
marker: 'arrow',
|
|
73
|
+
edit: {
|
|
74
|
+
subject: true,
|
|
75
|
+
label: true
|
|
76
|
+
},
|
|
77
|
+
seriesKey: '',
|
|
78
|
+
x: 50,
|
|
79
|
+
y: Number(newSvgDims?.[1] / 2),
|
|
80
|
+
xKey: config.xAxis.type === 'date' ? new Date(config?.data?.[0]?.[config.xAxis.dataKey]).getTime() : config.xAxis.type === 'categorical' ? '1/15/2016' : '',
|
|
81
|
+
yKey: '',
|
|
82
|
+
dx: 20,
|
|
83
|
+
dy: -20,
|
|
84
|
+
opacity: '100',
|
|
85
|
+
savedDimensions: newSvgDims,
|
|
86
|
+
connectionType: 'line'
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const annotations = Array.isArray(config.annotations) ? config.annotations : []
|
|
90
|
+
|
|
91
|
+
updateConfig({
|
|
92
|
+
...config,
|
|
93
|
+
annotations: [...annotations, newAnnotation]
|
|
94
|
+
})
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const handleRemoveAnnotation = (annotationIndex: number) => {
|
|
98
|
+
const updated = config.annotations.filter((_, index) => index !== annotationIndex)
|
|
99
|
+
updateConfig({
|
|
100
|
+
...config,
|
|
101
|
+
annotations: updated
|
|
102
|
+
})
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
return (
|
|
106
|
+
<Accordion key={props.name}>
|
|
107
|
+
<Accordion.Section title={props.name} key={props.name}>
|
|
108
|
+
<label key={`key-1`}>
|
|
109
|
+
Show Annotation Dropdown
|
|
110
|
+
<input
|
|
111
|
+
type='checkbox'
|
|
112
|
+
checked={config?.general?.showAnnotationDropdown || false}
|
|
113
|
+
onChange={e => {
|
|
114
|
+
updateConfig({
|
|
115
|
+
...config,
|
|
116
|
+
general: {
|
|
117
|
+
...config.general,
|
|
118
|
+
showAnnotationDropdown: e.target.checked
|
|
119
|
+
}
|
|
120
|
+
})
|
|
121
|
+
}}
|
|
122
|
+
/>
|
|
123
|
+
</label>
|
|
124
|
+
|
|
125
|
+
{config.general.showAnnotationDropdown && (
|
|
126
|
+
<label key={`key-2`}>
|
|
127
|
+
Annotation Dropdown Title:
|
|
128
|
+
<input
|
|
129
|
+
type='text'
|
|
130
|
+
style={{ marginBottom: '10px' }}
|
|
131
|
+
value={config?.general?.annotationDropdownText}
|
|
132
|
+
onChange={e => {
|
|
133
|
+
updateConfig({
|
|
134
|
+
...config,
|
|
135
|
+
general: {
|
|
136
|
+
...config.general,
|
|
137
|
+
annotationDropdownText: e.target.value
|
|
138
|
+
}
|
|
139
|
+
})
|
|
140
|
+
}}
|
|
141
|
+
/>
|
|
142
|
+
</label>
|
|
143
|
+
)}
|
|
144
|
+
{config?.annotations &&
|
|
145
|
+
config?.annotations.map((annotation, index) => (
|
|
146
|
+
<Accordion key={index}>
|
|
147
|
+
<Accordion.Section title={annotation.text ? annotation.text.substring(0, 15) + '...' : `Annotation ${index + 1}`}>
|
|
148
|
+
<div className='annotation-group'>
|
|
149
|
+
<label>
|
|
150
|
+
Annotation Text:
|
|
151
|
+
<textarea rows={5} value={annotation.text} onChange={e => handleAnnotationUpdate(e.target.value, 'text', index)} />
|
|
152
|
+
</label>
|
|
153
|
+
<label>
|
|
154
|
+
Opacity
|
|
155
|
+
<br />
|
|
156
|
+
<input
|
|
157
|
+
type='range'
|
|
158
|
+
onChange={e => {
|
|
159
|
+
const updatedAnnotations = _.cloneDeep(config?.annotations)
|
|
160
|
+
updatedAnnotations[index].opacity = e.target.value
|
|
161
|
+
updateConfig({
|
|
162
|
+
...config,
|
|
163
|
+
annotations: updatedAnnotations
|
|
164
|
+
})
|
|
165
|
+
}}
|
|
166
|
+
value={config?.annotations?.[index]?.opacity || '100'}
|
|
167
|
+
/>
|
|
168
|
+
</label>
|
|
169
|
+
|
|
170
|
+
<label>
|
|
171
|
+
Edit Subject
|
|
172
|
+
<input
|
|
173
|
+
type='checkbox'
|
|
174
|
+
checked={config?.annotations[index]?.edit?.subject || false}
|
|
175
|
+
onChange={e => {
|
|
176
|
+
const updatedAnnotations = _.cloneDeep(config?.annotations)
|
|
177
|
+
updatedAnnotations[index].edit.subject = e.target.checked
|
|
178
|
+
updateConfig({
|
|
179
|
+
...config,
|
|
180
|
+
annotations: updatedAnnotations
|
|
181
|
+
})
|
|
182
|
+
}}
|
|
183
|
+
/>
|
|
184
|
+
</label>
|
|
185
|
+
<label>
|
|
186
|
+
Edit Label
|
|
187
|
+
<input
|
|
188
|
+
type='checkbox'
|
|
189
|
+
checked={config?.annotations[index]?.edit?.label || false}
|
|
190
|
+
onChange={e => {
|
|
191
|
+
const updatedAnnotations = _.cloneDeep(config?.annotations)
|
|
192
|
+
updatedAnnotations[index].edit.label = e.target.checked
|
|
193
|
+
updateConfig({
|
|
194
|
+
...config,
|
|
195
|
+
annotations: updatedAnnotations
|
|
196
|
+
})
|
|
197
|
+
}}
|
|
198
|
+
/>
|
|
199
|
+
</label>
|
|
200
|
+
|
|
201
|
+
<label>
|
|
202
|
+
Connection Type:
|
|
203
|
+
<select
|
|
204
|
+
key='annotation-connection-type'
|
|
205
|
+
onChange={e => {
|
|
206
|
+
const updatedAnnotations = _.cloneDeep(config?.annotations)
|
|
207
|
+
updatedAnnotations[index].connectionType = e.target.value
|
|
208
|
+
updateConfig({
|
|
209
|
+
...config,
|
|
210
|
+
annotations: updatedAnnotations
|
|
211
|
+
})
|
|
212
|
+
}}
|
|
213
|
+
value={config?.annotations[index]?.connectionType}
|
|
214
|
+
>
|
|
215
|
+
<option key='select' value='select'>
|
|
216
|
+
Select
|
|
217
|
+
</option>
|
|
218
|
+
{['curve', 'line', 'elbow', 'none'].map((side, index) => (
|
|
219
|
+
<option key={side} value={side}>
|
|
220
|
+
{side}
|
|
221
|
+
</option>
|
|
222
|
+
))}
|
|
223
|
+
</select>
|
|
224
|
+
</label>
|
|
225
|
+
|
|
226
|
+
{annotation.connectionType === 'curve' && (
|
|
227
|
+
<>
|
|
228
|
+
<label>
|
|
229
|
+
Curve Control
|
|
230
|
+
{/* create a range input */}
|
|
231
|
+
<input
|
|
232
|
+
type='range'
|
|
233
|
+
min='-20'
|
|
234
|
+
max='20'
|
|
235
|
+
value={config?.annotations[index]?.bezier || 0}
|
|
236
|
+
onChange={e => {
|
|
237
|
+
const updatedAnnotations = _.cloneDeep(config?.annotations)
|
|
238
|
+
updatedAnnotations[index].bezier = e.target.value
|
|
239
|
+
updateConfig({
|
|
240
|
+
...config,
|
|
241
|
+
annotations: updatedAnnotations
|
|
242
|
+
})
|
|
243
|
+
}}
|
|
244
|
+
/>
|
|
245
|
+
</label>
|
|
246
|
+
</>
|
|
247
|
+
)}
|
|
248
|
+
|
|
249
|
+
{/* <label>
|
|
250
|
+
Connection Location:
|
|
251
|
+
<select
|
|
252
|
+
onChange={e => {
|
|
253
|
+
const updatedAnnotations = _.cloneDeep(config?.annotations)
|
|
254
|
+
updatedAnnotations[index].connectionLocation = e.target.value
|
|
255
|
+
updateConfig({
|
|
256
|
+
...config,
|
|
257
|
+
annotations: updatedAnnotations
|
|
258
|
+
})
|
|
259
|
+
}}
|
|
260
|
+
>
|
|
261
|
+
{['auto', 'left', 'top', 'bottom', 'right'].map((side, index) => (
|
|
262
|
+
<option key={side} value={side}>
|
|
263
|
+
{side}
|
|
264
|
+
</option>
|
|
265
|
+
))}
|
|
266
|
+
</select>
|
|
267
|
+
</label> */}
|
|
268
|
+
|
|
269
|
+
<label>
|
|
270
|
+
Marker
|
|
271
|
+
<select
|
|
272
|
+
key='annotation-marker'
|
|
273
|
+
value={annotation.marker}
|
|
274
|
+
onChange={e => {
|
|
275
|
+
const updatedAnnotations = _.cloneDeep(config?.annotations)
|
|
276
|
+
updatedAnnotations[index].marker = e.target.value
|
|
277
|
+
updateConfig({
|
|
278
|
+
...config,
|
|
279
|
+
annotations: updatedAnnotations
|
|
280
|
+
})
|
|
281
|
+
}}
|
|
282
|
+
>
|
|
283
|
+
{['arrow', 'circle'].map((column, columnIndex) => {
|
|
284
|
+
return <option key={`col-${columnIndex}`}>{column}</option>
|
|
285
|
+
})}
|
|
286
|
+
</select>
|
|
287
|
+
</label>
|
|
288
|
+
|
|
289
|
+
<Button className='warn btn-warn btn btn-remove delete' onClick={() => handleRemoveAnnotation(index)}>
|
|
290
|
+
Delete Annotation
|
|
291
|
+
</Button>
|
|
292
|
+
</div>
|
|
293
|
+
</Accordion.Section>
|
|
294
|
+
</Accordion>
|
|
295
|
+
))}
|
|
296
|
+
{config?.annotations?.length < 3 && (
|
|
297
|
+
<Button onClick={handleAddAnnotation} className='mt-2'>
|
|
298
|
+
Add Annotation
|
|
299
|
+
</Button>
|
|
300
|
+
)}
|
|
301
|
+
</Accordion.Section>
|
|
302
|
+
</Accordion>
|
|
303
|
+
)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export default PanelAnnotate
|
|
@@ -18,7 +18,7 @@ import { PanelProps } from '../PanelProps'
|
|
|
18
18
|
const PanelGeneral: FC<PanelProps> = props => {
|
|
19
19
|
const { config } = useContext(ConfigContext)
|
|
20
20
|
const { updateField } = useEditorPanelContext()
|
|
21
|
-
const { enabledChartTypes, visHasNumbersOnBars, visHasLabelOnData, visSupportsChartHeight, visSupportsSuperTitle, visSupportsFootnotes } = useEditorPermissions()
|
|
21
|
+
const { enabledChartTypes, visHasNumbersOnBars, visHasaAdditionalLabelsOnBars, visHasLabelOnData, visSupportsChartHeight, visSupportsSuperTitle, visSupportsFootnotes } = useEditorPermissions()
|
|
22
22
|
const { visualizationType, visualizationSubType, barStyle } = config
|
|
23
23
|
|
|
24
24
|
const showBarStyleOptions = () => {
|
|
@@ -37,21 +37,151 @@ const PanelGeneral: FC<PanelProps> = props => {
|
|
|
37
37
|
<AccordionItemButton>General</AccordionItemButton>
|
|
38
38
|
</AccordionItemHeading>
|
|
39
39
|
<AccordionItemPanel>
|
|
40
|
-
<Select value={visualizationType} fieldName='visualizationType' label='Chart Type' updateField={updateField} options={enabledChartTypes} />
|
|
40
|
+
{config?.visualizationType !== 'Sankey' && <Select value={visualizationType} fieldName='visualizationType' label='Chart Type' updateField={updateField} options={enabledChartTypes} />}
|
|
41
|
+
{visSupportsChartHeight() && config.orientation === 'vertical' && (
|
|
42
|
+
<TextField
|
|
43
|
+
type='number'
|
|
44
|
+
value={config.heights.vertical}
|
|
45
|
+
section='heights'
|
|
46
|
+
fieldName='vertical'
|
|
47
|
+
label='Chart Height'
|
|
48
|
+
updateField={updateField}
|
|
49
|
+
tooltip={
|
|
50
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
51
|
+
<Tooltip.Target>
|
|
52
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
53
|
+
</Tooltip.Target>
|
|
54
|
+
<Tooltip.Content>
|
|
55
|
+
<p>For some visualization types, such as the sankey diagram, it may be necessary to adjust to chart height for optimal display.</p>
|
|
56
|
+
</Tooltip.Content>
|
|
57
|
+
</Tooltip>
|
|
58
|
+
}
|
|
59
|
+
/>
|
|
60
|
+
)}
|
|
41
61
|
{(visualizationType === 'Bar' || visualizationType === 'Combo' || visualizationType === 'Area Chart') && <Select value={visualizationSubType || 'Regular'} fieldName='visualizationSubType' label='Chart Subtype' updateField={updateField} options={['regular', 'stacked']} />}
|
|
42
62
|
{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
63
|
{visualizationType === 'Bar' && <Select value={config.orientation || 'vertical'} fieldName='orientation' label='Orientation' updateField={updateField} options={['vertical', 'horizontal']} />}
|
|
44
64
|
{visualizationType === 'Deviation Bar' && <Select label='Orientation' options={['horizontal']} />}
|
|
45
|
-
{(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') &&
|
|
65
|
+
{(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && (
|
|
66
|
+
<Select
|
|
67
|
+
value={config.isLollipopChart ? 'lollipop' : barStyle || 'flat'}
|
|
68
|
+
fieldName='barStyle'
|
|
69
|
+
label='bar style'
|
|
70
|
+
updateField={updateField}
|
|
71
|
+
options={showBarStyleOptions()}
|
|
72
|
+
tooltip={
|
|
73
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
74
|
+
<Tooltip.Target>
|
|
75
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
76
|
+
</Tooltip.Target>
|
|
77
|
+
<Tooltip.Content>
|
|
78
|
+
<p>Consider using the 'Flat' bar style when presenting data that includes '0' values.</p>
|
|
79
|
+
</Tooltip.Content>
|
|
80
|
+
</Tooltip>
|
|
81
|
+
}
|
|
82
|
+
/>
|
|
83
|
+
)}
|
|
46
84
|
{(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && barStyle === 'rounded' && <Select value={config.tipRounding || 'top'} fieldName='tipRounding' label='tip rounding' updateField={updateField} options={['top', 'full']} />}
|
|
47
85
|
{(visualizationType === 'Bar' || visualizationType === 'Deviation Bar') && barStyle === 'rounded' && <Select value={config.roundingStyle || 'standard'} fieldName='roundingStyle' label='rounding style' updateField={updateField} options={['standard', 'shallow', 'finger']} />}
|
|
48
86
|
{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']} />}
|
|
49
87
|
{visHasNumbersOnBars() ? (
|
|
50
88
|
<CheckBox value={config.yAxis.displayNumbersOnBar} section='yAxis' fieldName='displayNumbersOnBar' label={config.isLollipopChart ? 'Display Numbers after Bar' : 'Display Numbers on Bar'} updateField={updateField} />
|
|
51
89
|
) : (
|
|
52
|
-
visHasLabelOnData() &&
|
|
90
|
+
visHasLabelOnData() && (
|
|
91
|
+
<CheckBox
|
|
92
|
+
value={config.labels}
|
|
93
|
+
fieldName='labels'
|
|
94
|
+
label='Display label on data'
|
|
95
|
+
updateField={updateField}
|
|
96
|
+
tooltip={
|
|
97
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
98
|
+
<Tooltip.Target>
|
|
99
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
100
|
+
</Tooltip.Target>
|
|
101
|
+
<Tooltip.Content>
|
|
102
|
+
<p>Selecting this option will not hide the display of "zero value", "suppressed data", or "missing data" indicators on the chart (if applicable).</p>
|
|
103
|
+
</Tooltip.Content>
|
|
104
|
+
</Tooltip>
|
|
105
|
+
}
|
|
106
|
+
/>
|
|
107
|
+
)
|
|
108
|
+
)}
|
|
109
|
+
{visHasaAdditionalLabelsOnBars() && (
|
|
110
|
+
<>
|
|
111
|
+
<CheckBox
|
|
112
|
+
tooltip={
|
|
113
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
114
|
+
<Tooltip.Target>
|
|
115
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
116
|
+
</Tooltip.Target>
|
|
117
|
+
<Tooltip.Content>
|
|
118
|
+
<p>Selecting this option will display 'N/A' on the Date/Category Axis, in the tooltip hover, and in the data table to indicate missing or undefined data values.</p>
|
|
119
|
+
</Tooltip.Content>
|
|
120
|
+
</Tooltip>
|
|
121
|
+
}
|
|
122
|
+
value={config.general.showMissingDataLabel}
|
|
123
|
+
section='general'
|
|
124
|
+
fieldName='showMissingDataLabel'
|
|
125
|
+
label='Display "Missing Data" Label'
|
|
126
|
+
updateField={updateField}
|
|
127
|
+
/>
|
|
128
|
+
<CheckBox
|
|
129
|
+
tooltip={
|
|
130
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
131
|
+
<Tooltip.Target>
|
|
132
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
133
|
+
</Tooltip.Target>
|
|
134
|
+
<Tooltip.Content>
|
|
135
|
+
<p> Selecting this option will display a thin line slightly above the Date/Category Axis to indicate "zero value" where zero values are indicated in the Data Series.</p>
|
|
136
|
+
</Tooltip.Content>
|
|
137
|
+
</Tooltip>
|
|
138
|
+
}
|
|
139
|
+
value={config.general.showZeroValueDataLabel}
|
|
140
|
+
section='general'
|
|
141
|
+
fieldName='showZeroValueDataLabel'
|
|
142
|
+
label='Display "Zero Value Data" Label'
|
|
143
|
+
updateField={updateField}
|
|
144
|
+
/>
|
|
145
|
+
|
|
146
|
+
<CheckBox
|
|
147
|
+
tooltip={
|
|
148
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
149
|
+
<Tooltip.Target>
|
|
150
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
151
|
+
</Tooltip.Target>
|
|
152
|
+
<Tooltip.Content>
|
|
153
|
+
<p>Selecting this option will display the 'suppressed data symbol' on the Date/Category Axis, in the tooltip hover, and in the data table where suppressed data values are indicated in the Data Series</p>
|
|
154
|
+
</Tooltip.Content>
|
|
155
|
+
</Tooltip>
|
|
156
|
+
}
|
|
157
|
+
value={config.general.showSuppressedSymbol}
|
|
158
|
+
section='general'
|
|
159
|
+
fieldName='showSuppressedSymbol'
|
|
160
|
+
label='Display "suppressed data" label'
|
|
161
|
+
updateField={updateField}
|
|
162
|
+
/>
|
|
163
|
+
</>
|
|
53
164
|
)}
|
|
165
|
+
|
|
54
166
|
{visualizationType === 'Pie' && <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />}
|
|
167
|
+
{visualizationType === 'Line' && (
|
|
168
|
+
<CheckBox
|
|
169
|
+
value={config.allowLineToBarGraph}
|
|
170
|
+
fieldName='allowLineToBarGraph'
|
|
171
|
+
label='Convert to Bar Graph'
|
|
172
|
+
updateField={updateField}
|
|
173
|
+
tooltip={
|
|
174
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
175
|
+
<Tooltip.Target>
|
|
176
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
177
|
+
</Tooltip.Target>
|
|
178
|
+
<Tooltip.Content>
|
|
179
|
+
<p>Switch to bar graph when less than 3 data points available.</p>
|
|
180
|
+
</Tooltip.Content>
|
|
181
|
+
</Tooltip>
|
|
182
|
+
}
|
|
183
|
+
/>
|
|
184
|
+
)}
|
|
55
185
|
|
|
56
186
|
<TextField
|
|
57
187
|
value={config.title || 'Chart Title'}
|
|
@@ -144,14 +274,12 @@ const PanelGeneral: FC<PanelProps> = props => {
|
|
|
144
274
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
145
275
|
</Tooltip.Target>
|
|
146
276
|
<Tooltip.Content>
|
|
147
|
-
<p>
|
|
277
|
+
<p>Consider adding footnotes when displaying 'suppressed,' 'no data,' and 'zero values' to ensure accurate interpretation of the data.</p>
|
|
148
278
|
</Tooltip.Content>
|
|
149
279
|
</Tooltip>
|
|
150
280
|
}
|
|
151
281
|
/>
|
|
152
282
|
)}
|
|
153
|
-
|
|
154
|
-
{visSupportsChartHeight() && config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
|
|
155
283
|
</AccordionItemPanel>
|
|
156
284
|
</AccordionItem>
|
|
157
285
|
)
|
|
@@ -64,6 +64,7 @@ const SankeySettings = () => {
|
|
|
64
64
|
<AccordionItemButton>Sankey Settings</AccordionItemButton>
|
|
65
65
|
</AccordionItemHeading>
|
|
66
66
|
<AccordionItemPanel>
|
|
67
|
+
<p>Node stories can provide additional details to support public health messaging. COVE can display a maximum of 3 node stories.</p>
|
|
67
68
|
{data?.storyNodeText &&
|
|
68
69
|
data?.storyNodeText.map(({ StoryNode, segmentTextBefore, segmentTextAfter }, i) => (
|
|
69
70
|
<div key={i} style={{ border: '1px solid black', margin: '15px auto', padding: '15px', borderRadius: '10px' }}>
|
|
@@ -84,7 +85,6 @@ const SankeySettings = () => {
|
|
|
84
85
|
</Button>
|
|
85
86
|
</div>
|
|
86
87
|
))}
|
|
87
|
-
{`Total Story Nodes: ${data?.storyNodeText?.length}`}
|
|
88
88
|
{data?.storyNodeText?.length < 3 && (
|
|
89
89
|
<button
|
|
90
90
|
type='button'
|
|
@@ -97,8 +97,7 @@ const SankeySettings = () => {
|
|
|
97
97
|
Add StoryNode
|
|
98
98
|
</button>
|
|
99
99
|
)}
|
|
100
|
-
|
|
101
|
-
<CheckBox value={config.enableTooltips} fieldName='enableTooltips' label='Enable Tooltips' updateField={updateField} />
|
|
100
|
+
{config.enableTooltips && config.data?.tooltips?.length > 0 && <CheckBox value={config.enableTooltips} fieldName='enableTooltips' label='Enable Tooltips' updateField={updateField} />}
|
|
102
101
|
</AccordionItemPanel>
|
|
103
102
|
</AccordionItem>
|
|
104
103
|
)
|
|
@@ -5,15 +5,14 @@ import ConfigContext from '../../../../ConfigContext'
|
|
|
5
5
|
import InputSelect from '@cdc/core/components/inputs/InputSelect'
|
|
6
6
|
import Check from '@cdc/core/assets/icon-check.svg'
|
|
7
7
|
import { approvedCurveTypes } from '@cdc/core/helpers/lineChartHelpers'
|
|
8
|
-
|
|
8
|
+
import { sequentialPalettes } from '@cdc/core/data/colorPalettes'
|
|
9
9
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
10
10
|
|
|
11
11
|
// Third Party
|
|
12
12
|
import { Accordion, AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
|
|
13
13
|
import { Draggable } from '@hello-pangea/dnd'
|
|
14
|
-
import { colorPalettesChart, sequentialPalettes } from '@cdc/core/data/colorPalettes'
|
|
15
14
|
|
|
16
|
-
const SeriesContext = React.createContext()
|
|
15
|
+
const SeriesContext = React.createContext({})
|
|
17
16
|
|
|
18
17
|
const SeriesWrapper = props => {
|
|
19
18
|
const { updateConfig, config, rawData } = useContext(ConfigContext)
|
|
@@ -456,8 +455,8 @@ const SeriesInputWeight = props => {
|
|
|
456
455
|
type='number'
|
|
457
456
|
key={`series-weight-${i}`}
|
|
458
457
|
value={series.weight ? series.weight : ''}
|
|
459
|
-
min=
|
|
460
|
-
max=
|
|
458
|
+
min='1'
|
|
459
|
+
max='9'
|
|
461
460
|
onChange={event => {
|
|
462
461
|
changeSeriesWeight(i, event.target.value, event.target.min, event.target.max)
|
|
463
462
|
}}
|
|
@@ -22,7 +22,8 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
22
22
|
const { config, updateConfig, colorPalettes, twoColorPalette } = useContext<ChartContext>(ConfigContext)
|
|
23
23
|
const { visual } = config
|
|
24
24
|
const { setLollipopShape, updateField } = useEditorPanelContext()
|
|
25
|
-
const { visHasBarBorders, visCanAnimate, visSupportsNonSequentialPallete, headerColors, visSupportsTooltipOpacity, visSupportsTooltipLines, visSupportsBarSpace, visSupportsBarThickness, visHasDataCutoff, visSupportsSequentialPallete, visSupportsReverseColorPalette } =
|
|
25
|
+
const { visHasBarBorders, visCanAnimate, visSupportsNonSequentialPallete, headerColors, visSupportsTooltipOpacity, visSupportsTooltipLines, visSupportsBarSpace, visSupportsBarThickness, visHasDataCutoff, visSupportsSequentialPallete, visSupportsReverseColorPalette, visHasSingleSeriesTooltip } =
|
|
26
|
+
useEditorPermissions()
|
|
26
27
|
const { twoColorPalettes, sequential, nonSequential } = useColorPalette(config, updateConfig)
|
|
27
28
|
|
|
28
29
|
const updateColor = (property, _value) => {
|
|
@@ -312,7 +313,7 @@ const PanelVisual: FC<PanelProps> = props => {
|
|
|
312
313
|
/>
|
|
313
314
|
</label>
|
|
314
315
|
)}
|
|
315
|
-
{
|
|
316
|
+
{visHasSingleSeriesTooltip() && <CheckBox value={config.tooltips.singleSeries} fieldName='singleSeries' section='tooltips' label='SHOW HOVER FOR SINGLE DATA SERIES' updateField={updateField} />}
|
|
316
317
|
|
|
317
318
|
<label>
|
|
318
319
|
<span className='edit-label column-heading'>No Data Message</span>
|
|
@@ -5,6 +5,7 @@ import General from './Panel.General'
|
|
|
5
5
|
import BoxPlot from './Panel.BoxPlot'
|
|
6
6
|
import Visual from './Panel.Visual'
|
|
7
7
|
import Sankey from './Panel.Sankey'
|
|
8
|
+
import Annotate from './Panel.Annotate'
|
|
8
9
|
|
|
9
10
|
const Panels = {
|
|
10
11
|
ForestPlot: ForestPlotSettings,
|
|
@@ -13,7 +14,8 @@ const Panels = {
|
|
|
13
14
|
General,
|
|
14
15
|
BoxPlot,
|
|
15
16
|
Visual,
|
|
16
|
-
Sankey
|
|
17
|
+
Sankey,
|
|
18
|
+
Annotate
|
|
17
19
|
}
|
|
18
20
|
|
|
19
21
|
export default Panels
|
|
@@ -12,4 +12,23 @@
|
|
|
12
12
|
padding-left: 350px;
|
|
13
13
|
}
|
|
14
14
|
}
|
|
15
|
+
|
|
16
|
+
.viewport-overrides {
|
|
17
|
+
button {
|
|
18
|
+
width: 100%;
|
|
19
|
+
padding: 1em;
|
|
20
|
+
margin-top: 1em;
|
|
21
|
+
text-align: left;
|
|
22
|
+
|
|
23
|
+
span {
|
|
24
|
+
display: inline-block;
|
|
25
|
+
float: right;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.edit-block {
|
|
30
|
+
margin-top: 0;
|
|
31
|
+
padding: 1em;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
15
34
|
}
|
|
@@ -76,6 +76,11 @@ export const useEditorPermissions = () => {
|
|
|
76
76
|
return false
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
const visHasaAdditionalLabelsOnBars = () => {
|
|
80
|
+
if (['Bar', 'Combo', 'Line'].includes(config.visualizationType)) return true
|
|
81
|
+
return false
|
|
82
|
+
}
|
|
83
|
+
|
|
79
84
|
const visHasAnchors = () => {
|
|
80
85
|
switch (visualizationType) {
|
|
81
86
|
case 'Area Chart':
|
|
@@ -103,7 +108,7 @@ export const useEditorPermissions = () => {
|
|
|
103
108
|
}
|
|
104
109
|
|
|
105
110
|
const visHasBarBorders = () => {
|
|
106
|
-
const disabledCharts = ['Box Plot', 'Scatter Plot', 'Pie']
|
|
111
|
+
const disabledCharts = ['Box Plot', 'Scatter Plot', 'Pie', 'Line']
|
|
107
112
|
if (disabledCharts.includes(visualizationType)) return false
|
|
108
113
|
return series?.some(series => series.type === 'Bar' || series.type === 'Paired Bar' || series.type === 'Deviation Bar')
|
|
109
114
|
}
|
|
@@ -301,8 +306,21 @@ export const useEditorPermissions = () => {
|
|
|
301
306
|
if (visualizationType === 'Line') {
|
|
302
307
|
return true
|
|
303
308
|
}
|
|
309
|
+
if (visualizationType === 'Bar' && visualizationSubType === 'regular') {
|
|
310
|
+
return true
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (visualizationType === 'Combo') {
|
|
314
|
+
return true
|
|
315
|
+
}
|
|
316
|
+
return false
|
|
317
|
+
}
|
|
304
318
|
|
|
305
|
-
|
|
319
|
+
const visHasSingleSeriesTooltip = () => {
|
|
320
|
+
if (visualizationType === 'Bar' || visualizationType === 'Line') {
|
|
321
|
+
return true
|
|
322
|
+
}
|
|
323
|
+
if (visualizationType === 'Area Chart' && visualizationSubType === 'stacked') {
|
|
306
324
|
return true
|
|
307
325
|
}
|
|
308
326
|
return false
|
|
@@ -321,6 +339,7 @@ export const useEditorPermissions = () => {
|
|
|
321
339
|
visHasLegendAxisAlign,
|
|
322
340
|
visHasBrushChart,
|
|
323
341
|
visHasNumbersOnBars,
|
|
342
|
+
visHasaAdditionalLabelsOnBars,
|
|
324
343
|
visSupportsBarSpace,
|
|
325
344
|
visSupportsBarThickness,
|
|
326
345
|
visSupportsChartHeight,
|
|
@@ -352,6 +371,7 @@ export const useEditorPermissions = () => {
|
|
|
352
371
|
visSupportsValueAxisTicks,
|
|
353
372
|
visSupportsReactTooltip,
|
|
354
373
|
visSupportsValueAxisMax,
|
|
355
|
-
visSupportsValueAxisMin
|
|
374
|
+
visSupportsValueAxisMin,
|
|
375
|
+
visHasSingleSeriesTooltip
|
|
356
376
|
}
|
|
357
377
|
}
|