@cdc/chart 4.24.5 → 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 +39128 -35959
- package/examples/feature/annotations/index.json +542 -0
- package/examples/xaxis.json +493 -0
- package/index.html +5 -4
- package/package.json +5 -4
- package/src/CdcChart.tsx +104 -64
- 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/src/_stories/_mock/annotation_date-time_mock.json +530 -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 +1 -1
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +44 -42
- 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 +50 -22
- package/src/components/BarChart/helpers/index.ts +102 -0
- package/src/components/EditorPanel/EditorPanel.tsx +232 -98
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +306 -0
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +117 -6
- package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +2 -3
- 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 +19 -2
- package/src/components/Legend/Legend.Component.tsx +7 -8
- package/src/components/Legend/helpers/createFormatLabels.tsx +1 -1
- package/src/components/Legend/helpers/index.ts +5 -0
- package/src/components/LineChart/LineChartProps.ts +3 -0
- package/src/components/LineChart/helpers.ts +21 -7
- package/src/components/LineChart/index.tsx +7 -7
- package/src/components/LinearChart.jsx +179 -136
- 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 +90 -44
- 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} +2 -40
- package/src/hooks/useColorScale.ts +1 -1
- package/src/hooks/useMinMax.ts +8 -3
- package/src/hooks/useScales.ts +25 -3
- package/src/hooks/useTooltip.tsx +58 -11
- package/src/scss/main.scss +21 -14
- package/src/types/ChartConfig.ts +50 -3
- package/src/types/ChartContext.ts +9 -0
- package/tests-examples/helpers/testZeroValue.test.ts +30 -0
- package/LICENSE +0 -201
- 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,12 +37,50 @@ 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']} />}
|
|
@@ -61,14 +99,89 @@ const PanelGeneral: FC<PanelProps> = props => {
|
|
|
61
99
|
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
62
100
|
</Tooltip.Target>
|
|
63
101
|
<Tooltip.Content>
|
|
64
|
-
<p>Selecting this option will not hide the display of "zero value", "suppressed data", or "
|
|
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>
|
|
65
103
|
</Tooltip.Content>
|
|
66
104
|
</Tooltip>
|
|
67
105
|
}
|
|
68
106
|
/>
|
|
69
107
|
)
|
|
70
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
|
+
</>
|
|
164
|
+
)}
|
|
165
|
+
|
|
71
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
|
+
)}
|
|
72
185
|
|
|
73
186
|
<TextField
|
|
74
187
|
value={config.title || 'Chart Title'}
|
|
@@ -167,8 +280,6 @@ const PanelGeneral: FC<PanelProps> = props => {
|
|
|
167
280
|
}
|
|
168
281
|
/>
|
|
169
282
|
)}
|
|
170
|
-
|
|
171
|
-
{visSupportsChartHeight() && config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
|
|
172
283
|
</AccordionItemPanel>
|
|
173
284
|
</AccordionItem>
|
|
174
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
|
)
|
|
@@ -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
|
}
|
|
@@ -311,6 +316,16 @@ export const useEditorPermissions = () => {
|
|
|
311
316
|
return false
|
|
312
317
|
}
|
|
313
318
|
|
|
319
|
+
const visHasSingleSeriesTooltip = () => {
|
|
320
|
+
if (visualizationType === 'Bar' || visualizationType === 'Line') {
|
|
321
|
+
return true
|
|
322
|
+
}
|
|
323
|
+
if (visualizationType === 'Area Chart' && visualizationSubType === 'stacked') {
|
|
324
|
+
return true
|
|
325
|
+
}
|
|
326
|
+
return false
|
|
327
|
+
}
|
|
328
|
+
|
|
314
329
|
return {
|
|
315
330
|
enabledChartTypes,
|
|
316
331
|
headerColors,
|
|
@@ -324,6 +339,7 @@ export const useEditorPermissions = () => {
|
|
|
324
339
|
visHasLegendAxisAlign,
|
|
325
340
|
visHasBrushChart,
|
|
326
341
|
visHasNumbersOnBars,
|
|
342
|
+
visHasaAdditionalLabelsOnBars,
|
|
327
343
|
visSupportsBarSpace,
|
|
328
344
|
visSupportsBarThickness,
|
|
329
345
|
visSupportsChartHeight,
|
|
@@ -355,6 +371,7 @@ export const useEditorPermissions = () => {
|
|
|
355
371
|
visSupportsValueAxisTicks,
|
|
356
372
|
visSupportsReactTooltip,
|
|
357
373
|
visSupportsValueAxisMax,
|
|
358
|
-
visSupportsValueAxisMin
|
|
374
|
+
visSupportsValueAxisMin,
|
|
375
|
+
visHasSingleSeriesTooltip
|
|
359
376
|
}
|
|
360
377
|
}
|