@cdc/chart 4.24.4 → 4.24.5
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 +32130 -31726
- package/index.html +7 -7
- package/package.json +2 -2
- package/src/CdcChart.tsx +17 -13
- package/src/_stories/Chart.stories.tsx +8 -0
- package/src/_stories/_mock/bar-chart-suppressed.json +474 -0
- package/src/components/AreaChart/components/AreaChart.jsx +2 -2
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +52 -47
- package/src/components/BarChart/components/BarChart.Vertical.tsx +77 -92
- package/src/components/DeviationBar.jsx +4 -2
- package/src/components/EditorPanel/EditorPanel.tsx +289 -601
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +19 -2
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -5
- package/src/components/EditorPanel/useEditorPermissions.js +4 -1
- package/src/components/Legend/Legend.Component.tsx +62 -10
- package/src/components/LineChart/LineChartProps.ts +13 -6
- package/src/components/LineChart/components/LineChart.Circle.tsx +22 -11
- package/src/components/LineChart/helpers.ts +134 -10
- package/src/components/LineChart/index.tsx +69 -42
- package/src/components/LinearChart.jsx +155 -139
- package/src/components/ZoomBrush.tsx +40 -21
- package/src/data/initial-state.js +4 -4
- package/src/hooks/useBarChart.js +47 -22
- package/src/hooks/useMinMax.ts +21 -2
- package/src/hooks/useScales.ts +23 -23
- package/src/hooks/useTooltip.tsx +11 -11
- package/src/scss/main.scss +56 -6
- package/src/types/ChartConfig.ts +3 -13
- package/src/types/ChartContext.ts +4 -0
- 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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback, memo, useContext } from 'react'
|
|
2
|
-
import { DragDropContext, Droppable
|
|
2
|
+
import { DragDropContext, Droppable } from '@hello-pangea/dnd'
|
|
3
3
|
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
4
4
|
import { Accordion, AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
|
|
5
5
|
import Layout from '@cdc/core/components/Layout'
|
|
@@ -8,18 +8,17 @@ import Layout from '@cdc/core/components/Layout'
|
|
|
8
8
|
import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
|
|
9
9
|
import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
|
|
10
10
|
import Icon from '@cdc/core/components/ui/Icon'
|
|
11
|
-
import
|
|
11
|
+
import ColumnsEditor from '@cdc/core/components/EditorPanel/ColumnsEditor'
|
|
12
|
+
import DataTableEditor from '@cdc/core/components/EditorPanel/DataTableEditor'
|
|
13
|
+
import VizFilterEditor from '@cdc/core/components/EditorPanel/VizFilterEditor'
|
|
12
14
|
import Tooltip from '@cdc/core/components/ui/Tooltip'
|
|
13
15
|
import { Select, TextField, CheckBox } from '@cdc/core/components/EditorPanel/Inputs'
|
|
14
16
|
|
|
15
17
|
// chart components
|
|
16
18
|
import Panels from './components/Panels'
|
|
17
|
-
import Series from './components/Panel.Series.jsx'
|
|
18
19
|
|
|
19
20
|
// cdc additional
|
|
20
|
-
import { useColorPalette } from '../../hooks/useColorPalette'
|
|
21
21
|
import { useEditorPermissions } from './useEditorPermissions'
|
|
22
|
-
import { useFilters } from '@cdc/core/components/Filters'
|
|
23
22
|
import { useHighlightedBars } from '../../hooks/useHighlightedBars'
|
|
24
23
|
import ConfigContext from '../../ConfigContext'
|
|
25
24
|
import useReduceData from '../../hooks/useReduceData'
|
|
@@ -27,113 +26,57 @@ import useRightAxis from '../../hooks/useRightAxis'
|
|
|
27
26
|
import WarningImage from '../../images/warning.svg'
|
|
28
27
|
import useMinMax from '../../hooks/useMinMax'
|
|
29
28
|
|
|
30
|
-
import { type ChartConfig } from '../../types/ChartConfig'
|
|
31
29
|
import { type ChartContext } from '../../types/ChartContext'
|
|
30
|
+
import { type ChartConfig } from '../../types/ChartConfig'
|
|
32
31
|
|
|
33
32
|
import './editor-panel.scss'
|
|
34
33
|
import { Anchor } from '@cdc/core/types/Axis'
|
|
35
|
-
import DataTableEditor from '@cdc/core/components/EditorPanel/DataTableEditor'
|
|
36
34
|
import EditorPanelContext from './EditorPanelContext'
|
|
35
|
+
import _ from 'lodash'
|
|
36
|
+
import { adjustedSymbols as symbolCodes } from '@cdc/core/helpers/footnoteSymbols'
|
|
37
37
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
keys.add(key)
|
|
44
|
-
})
|
|
45
|
-
})
|
|
46
|
-
return [...keys]
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const getIconOptions = () => {
|
|
50
|
-
return ['star']
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
let removeColumn = i => {
|
|
54
|
-
let suppressedData = []
|
|
55
|
-
|
|
56
|
-
if (config.suppressedData) {
|
|
57
|
-
suppressedData = [...config.suppressedData]
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
suppressedData.splice(i, 1)
|
|
38
|
+
interface PreliminaryProps {
|
|
39
|
+
config: ChartConfig
|
|
40
|
+
updateConfig: Function
|
|
41
|
+
data: Record<string, any>[]
|
|
42
|
+
}
|
|
61
43
|
|
|
62
|
-
|
|
63
|
-
|
|
44
|
+
const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, data }) => {
|
|
45
|
+
const isCombo = config.visualizationType === 'Combo'
|
|
46
|
+
const lineSeriesExists = config.runtime.lineSeriesKeys?.length > 0
|
|
47
|
+
const barSeriesExists = config.runtime.barSeriesKeys?.length > 0
|
|
48
|
+
const hasComboLineSeries = isCombo && lineSeriesExists
|
|
49
|
+
const hasComboBarSeries = isCombo && barSeriesExists
|
|
64
50
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
suppressedData.push({ label: '', column: '', value: '', icon: '' })
|
|
68
|
-
updateConfig({ ...config, suppressedData })
|
|
51
|
+
const getColumnOptions = () => {
|
|
52
|
+
return _.uniq(_.flatMap(data, _.keys))
|
|
69
53
|
}
|
|
70
54
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (config.suppressedData) {
|
|
75
|
-
suppressedData = [...config.suppressedData]
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
suppressedData[i][fieldName] = value
|
|
79
|
-
updateConfig({ ...config, suppressedData })
|
|
55
|
+
const getTypeOptions = () => {
|
|
56
|
+
return config.visualizationType === 'Line' || hasComboLineSeries ? ['effect', 'suppression'] : ['suppression']
|
|
80
57
|
}
|
|
81
58
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
<div key={`suppressed-${i}`} className='edit-block'>
|
|
88
|
-
<button
|
|
89
|
-
type='button'
|
|
90
|
-
className='remove-column'
|
|
91
|
-
onClick={event => {
|
|
92
|
-
event.preventDefault()
|
|
93
|
-
removeColumn(i)
|
|
94
|
-
}}
|
|
95
|
-
>
|
|
96
|
-
Remove
|
|
97
|
-
</button>
|
|
98
|
-
<Select value={column} initial='Select' fieldName='column' label='Column' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} options={getColumnOptions()} />
|
|
99
|
-
<TextField value={value} fieldName='value' label='Value' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} />
|
|
100
|
-
<Select value={icon} initial='Select' fieldName='icon' label='Icon' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} options={getIconOptions()} />
|
|
101
|
-
<TextField value={label} fieldName='label' label='Label' placeholder='suppressed' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} />
|
|
102
|
-
</div>
|
|
103
|
-
)
|
|
104
|
-
})}
|
|
105
|
-
|
|
106
|
-
<button type='button' onClick={addColumn} className='btn full-width'>
|
|
107
|
-
Add Suppression Class
|
|
108
|
-
</button>
|
|
109
|
-
</>
|
|
110
|
-
)
|
|
111
|
-
})
|
|
112
|
-
const PreliminaryData = memo(({ config, updateConfig, data }) => {
|
|
113
|
-
const getColumnOptions = () => {
|
|
114
|
-
const keys = new Set()
|
|
115
|
-
data.forEach(d => {
|
|
116
|
-
Object.keys(d).forEach(key => {
|
|
117
|
-
keys.add(key)
|
|
118
|
-
})
|
|
119
|
-
})
|
|
120
|
-
return [...keys]
|
|
59
|
+
const lineCodes = {
|
|
60
|
+
'Dashed Small': '\u002D \u002D \u002D',
|
|
61
|
+
'Dashed Medium': '\u2013 \u2013',
|
|
62
|
+
'Dashed Large': '\u2014 \u2013',
|
|
63
|
+
'Open Circles': '\u25EF'
|
|
121
64
|
}
|
|
122
65
|
|
|
123
|
-
const
|
|
124
|
-
if (config.visualizationType === 'Line' ||
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
66
|
+
const getStyleOptions = type => {
|
|
67
|
+
if (config.visualizationType === 'Line' || isCombo) {
|
|
68
|
+
const options = Object.keys(lineCodes)
|
|
69
|
+
if (type === 'suppression') {
|
|
70
|
+
return options.slice(0, -1)
|
|
71
|
+
} else {
|
|
72
|
+
return options
|
|
73
|
+
}
|
|
128
74
|
}
|
|
129
75
|
}
|
|
130
76
|
|
|
131
|
-
const
|
|
132
|
-
if (config.visualizationType === '
|
|
133
|
-
return
|
|
134
|
-
}
|
|
135
|
-
if (config.visualizationType === 'Bar') {
|
|
136
|
-
return ['star']
|
|
77
|
+
const getSymbolOptions = () => {
|
|
78
|
+
if (config.visualizationType === 'Bar' || hasComboBarSeries) {
|
|
79
|
+
return Object.keys(symbolCodes)
|
|
137
80
|
}
|
|
138
81
|
}
|
|
139
82
|
|
|
@@ -150,8 +93,23 @@ const PreliminaryData = memo(({ config, updateConfig, data }) => {
|
|
|
150
93
|
}
|
|
151
94
|
|
|
152
95
|
let addColumn = () => {
|
|
96
|
+
const defaultType = config.visualizationType === 'Line' ? 'effect' : 'suppression'
|
|
153
97
|
let preliminaryData = config.preliminaryData ? [...config.preliminaryData] : []
|
|
154
|
-
|
|
98
|
+
const defaultValues = {
|
|
99
|
+
type: defaultType,
|
|
100
|
+
seriesKey: '',
|
|
101
|
+
label: 'Suppressed',
|
|
102
|
+
column: '',
|
|
103
|
+
value: '',
|
|
104
|
+
style: '',
|
|
105
|
+
displayTooltip: true,
|
|
106
|
+
displayLegend: true,
|
|
107
|
+
displayTable: true,
|
|
108
|
+
symbol: '',
|
|
109
|
+
iconCode: '',
|
|
110
|
+
lineCode: ''
|
|
111
|
+
}
|
|
112
|
+
preliminaryData.push(defaultValues)
|
|
155
113
|
updateConfig({ ...config, preliminaryData })
|
|
156
114
|
}
|
|
157
115
|
|
|
@@ -163,15 +121,22 @@ const PreliminaryData = memo(({ config, updateConfig, data }) => {
|
|
|
163
121
|
}
|
|
164
122
|
|
|
165
123
|
preliminaryData[i][fieldName] = value
|
|
124
|
+
if (fieldName === 'symbol') {
|
|
125
|
+
preliminaryData[i]['iconCode'] = symbolCodes[value]
|
|
126
|
+
}
|
|
127
|
+
if (fieldName === 'style') {
|
|
128
|
+
preliminaryData[i]['lineCode'] = lineCodes[value]
|
|
129
|
+
}
|
|
166
130
|
updateConfig({ ...config, preliminaryData })
|
|
167
131
|
}
|
|
168
132
|
|
|
169
133
|
return (
|
|
170
134
|
<>
|
|
171
135
|
{config.preliminaryData &&
|
|
172
|
-
config.preliminaryData
|
|
136
|
+
config.preliminaryData?.map(({ column, displayLegend, displayTable, displayTooltip, label, seriesKey, style, symbol, type, value }, i) => {
|
|
173
137
|
return (
|
|
174
138
|
<div key={`preliminaryData-${i}`} className='edit-block'>
|
|
139
|
+
<p> {type === 'suppression' ? 'Suppressed' : 'Effect'} Data</p>
|
|
175
140
|
<button
|
|
176
141
|
type='button'
|
|
177
142
|
className='remove-column'
|
|
@@ -182,23 +147,156 @@ const PreliminaryData = memo(({ config, updateConfig, data }) => {
|
|
|
182
147
|
>
|
|
183
148
|
Remove
|
|
184
149
|
</button>
|
|
185
|
-
<Select value={type} initial='Select' fieldName='type' label='Type' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} options={getTypeOptions()} />
|
|
186
|
-
<Select value={seriesKey} initial='Select' fieldName='seriesKey' label='ASSOCIATE TO SERIES' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} options={config.runtime.lineSeriesKeys ?? config.runtime?.seriesKeys} />
|
|
187
|
-
<Select value={column} initial='Select' fieldName='column' label='COLUMN WITH CONFIGURATION VALUE' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} options={getColumnOptions()} />
|
|
188
|
-
<TextField value={value} fieldName='value' label='VALUE TO TRIGGER' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} />
|
|
189
|
-
<Select value={style} initial='Select' fieldName='style' label='Style' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} options={getStyleOptions()} />
|
|
190
150
|
|
|
191
|
-
<
|
|
151
|
+
<Select value={type} initial={config.visualizationType == 'Bar' ? '' : 'Select'} fieldName='type' label='Type' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} options={getTypeOptions()} />
|
|
152
|
+
{type === 'suppression' ? (
|
|
153
|
+
<>
|
|
154
|
+
<Select
|
|
155
|
+
tooltip={
|
|
156
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
157
|
+
<Tooltip.Target>
|
|
158
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
159
|
+
</Tooltip.Target>
|
|
160
|
+
<Tooltip.Content>
|
|
161
|
+
<p>If no “Data Series" is selected, the symbol will be applied to "all" suppressed values indicated in the dataset.</p>
|
|
162
|
+
</Tooltip.Content>
|
|
163
|
+
</Tooltip>
|
|
164
|
+
}
|
|
165
|
+
value={column}
|
|
166
|
+
initial='Select'
|
|
167
|
+
fieldName='column'
|
|
168
|
+
label='Add Data Series'
|
|
169
|
+
updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
|
|
170
|
+
options={config.runtime?.seriesKeys}
|
|
171
|
+
/>
|
|
172
|
+
<TextField value={value} fieldName='value' label='Suppressed Data Value' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} />
|
|
173
|
+
{(hasComboLineSeries || config.visualizationType === 'Line') && (
|
|
174
|
+
<Select
|
|
175
|
+
tooltip={
|
|
176
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
177
|
+
<Tooltip.Target>
|
|
178
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
179
|
+
</Tooltip.Target>
|
|
180
|
+
<Tooltip.Content>
|
|
181
|
+
<p>The recommended approach for presenting data is to include a footnote indicating any data suppression.</p>
|
|
182
|
+
</Tooltip.Content>
|
|
183
|
+
</Tooltip>
|
|
184
|
+
}
|
|
185
|
+
value={style}
|
|
186
|
+
initial='Select'
|
|
187
|
+
fieldName='style'
|
|
188
|
+
label={'suppression line style'}
|
|
189
|
+
updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
|
|
190
|
+
options={getStyleOptions(type)}
|
|
191
|
+
/>
|
|
192
|
+
)}
|
|
193
|
+
|
|
194
|
+
{(hasComboBarSeries || config.visualizationType === 'Bar') && (
|
|
195
|
+
<Select
|
|
196
|
+
tooltip={
|
|
197
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
198
|
+
<Tooltip.Target>
|
|
199
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
200
|
+
</Tooltip.Target>
|
|
201
|
+
<Tooltip.Content>
|
|
202
|
+
<p>The suggested method for presenting suppressed data is to use "double asterisks". If "double asterisks" are already used elsewhere (e.g., footnotes), please select an alternative symbol from the menu to denote data suppression.</p>
|
|
203
|
+
</Tooltip.Content>
|
|
204
|
+
</Tooltip>
|
|
205
|
+
}
|
|
206
|
+
value={symbol}
|
|
207
|
+
initial='Select'
|
|
208
|
+
fieldName='symbol'
|
|
209
|
+
label={config.visualizationType === 'Combo' ? 'suppression bar symbol' : 'suppression symbol'}
|
|
210
|
+
updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
|
|
211
|
+
options={getSymbolOptions()}
|
|
212
|
+
/>
|
|
213
|
+
)}
|
|
214
|
+
|
|
215
|
+
<TextField
|
|
216
|
+
tooltip={
|
|
217
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
218
|
+
<Tooltip.Target>
|
|
219
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
220
|
+
</Tooltip.Target>
|
|
221
|
+
<Tooltip.Content>
|
|
222
|
+
<p>This label will display in the tooltip and legend.</p>
|
|
223
|
+
</Tooltip.Content>
|
|
224
|
+
</Tooltip>
|
|
225
|
+
}
|
|
226
|
+
value={label ? label : 'Suppressed'}
|
|
227
|
+
fieldName='label'
|
|
228
|
+
label='Suppressed Data Label'
|
|
229
|
+
placeholder=''
|
|
230
|
+
updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
|
|
231
|
+
/>
|
|
232
|
+
<CheckBox
|
|
233
|
+
tooltip={
|
|
234
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
235
|
+
<Tooltip.Target>
|
|
236
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
237
|
+
</Tooltip.Target>
|
|
238
|
+
<Tooltip.Content>
|
|
239
|
+
<p>Enabling this tooltip will provide a clearer indication of 'suppressed' or 'zero data' values, whichever is applicable. Deselecting 'Display In Tooltip' indicates that you do not want to display 'suppressed' or 'zero data' values in tooltips when hovering over them.</p>
|
|
240
|
+
</Tooltip.Content>
|
|
241
|
+
</Tooltip>
|
|
242
|
+
}
|
|
243
|
+
value={displayTooltip}
|
|
244
|
+
fieldName='displayTooltip'
|
|
245
|
+
label='Display in tooltips'
|
|
246
|
+
updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
|
|
247
|
+
/>
|
|
248
|
+
<CheckBox
|
|
249
|
+
tooltip={
|
|
250
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
251
|
+
<Tooltip.Target>
|
|
252
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
253
|
+
</Tooltip.Target>
|
|
254
|
+
<Tooltip.Content>
|
|
255
|
+
<p>Deselecting "Display in Legend" indicates that you do not want to display suppressed data in the legend.</p>
|
|
256
|
+
</Tooltip.Content>
|
|
257
|
+
</Tooltip>
|
|
258
|
+
}
|
|
259
|
+
value={displayLegend}
|
|
260
|
+
fieldName='displayLegend'
|
|
261
|
+
label='Display in legend'
|
|
262
|
+
updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
|
|
263
|
+
/>
|
|
264
|
+
<CheckBox
|
|
265
|
+
tooltip={
|
|
266
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
267
|
+
<Tooltip.Target>
|
|
268
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
269
|
+
</Tooltip.Target>
|
|
270
|
+
<Tooltip.Content>
|
|
271
|
+
<p>Deselecting "Display In Data Table" indicates that you do not want to display suppressed data in the data table.</p>
|
|
272
|
+
</Tooltip.Content>
|
|
273
|
+
</Tooltip>
|
|
274
|
+
}
|
|
275
|
+
value={displayTable}
|
|
276
|
+
fieldName='displayTable'
|
|
277
|
+
label='Display in table'
|
|
278
|
+
updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
|
|
279
|
+
/>
|
|
280
|
+
</>
|
|
281
|
+
) : (
|
|
282
|
+
<>
|
|
283
|
+
<Select value={seriesKey} initial='Select' fieldName='seriesKey' label='ASSOCIATE TO SERIES' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} options={config.runtime.lineSeriesKeys ?? config.runtime?.seriesKeys} />
|
|
284
|
+
<Select value={column} initial='Select' fieldName='column' label='COLUMN WITH CONFIGURATION VALUE' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} options={getColumnOptions()} />
|
|
285
|
+
<TextField value={value} fieldName='value' label='VALUE TO TRIGGER' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} />
|
|
286
|
+
<Select value={style} initial='Select' fieldName='style' label='Style' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} options={getStyleOptions(type)} />
|
|
287
|
+
<TextField value={label} fieldName='label' label='Label' placeholder='' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} />
|
|
288
|
+
</>
|
|
289
|
+
)}
|
|
192
290
|
</div>
|
|
193
291
|
)
|
|
194
292
|
})}
|
|
195
293
|
|
|
196
294
|
<button type='button' onClick={addColumn} className='btn full-width'>
|
|
197
|
-
{config.visualizationType === 'Line'
|
|
295
|
+
{config.visualizationType === 'Line' ? 'Add Special Line' : config.visualizationType === 'Bar' ? ' Add Special Bar' : 'Add Special Bar/Line'}
|
|
198
296
|
</button>
|
|
199
297
|
</>
|
|
200
298
|
)
|
|
201
|
-
}
|
|
299
|
+
}
|
|
202
300
|
|
|
203
301
|
const EditorPanel = () => {
|
|
204
302
|
const {
|
|
@@ -224,9 +322,6 @@ const EditorPanel = () => {
|
|
|
224
322
|
} = useContext<ChartContext>(ConfigContext)
|
|
225
323
|
|
|
226
324
|
const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
|
|
227
|
-
|
|
228
|
-
const { twoColorPalettes, sequential, nonSequential } = useColorPalette(config, updateConfig)
|
|
229
|
-
|
|
230
325
|
const properties = { data, config }
|
|
231
326
|
const { leftMax, rightMax } = useMinMax(properties)
|
|
232
327
|
|
|
@@ -276,9 +371,6 @@ const EditorPanel = () => {
|
|
|
276
371
|
visHasDataSuppression
|
|
277
372
|
} = useEditorPermissions()
|
|
278
373
|
|
|
279
|
-
// argument acts as props
|
|
280
|
-
const { handleFilterOrder, filterOrderOptions, filterStyleOptions } = useFilters({ config, setConfig: updateConfig, filteredData: data, setFilteredData })
|
|
281
|
-
|
|
282
374
|
// when the visualization type changes we
|
|
283
375
|
// have to update the individual series type & axis details
|
|
284
376
|
// dataKey is unchanged here.
|
|
@@ -389,13 +481,18 @@ const EditorPanel = () => {
|
|
|
389
481
|
return
|
|
390
482
|
}
|
|
391
483
|
|
|
392
|
-
|
|
484
|
+
const truthy = val => {
|
|
485
|
+
if (val === 0) return true // indexes can be used as keys
|
|
486
|
+
return !!val
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
if (section === 'columns' && truthy(subsection) && truthy(fieldName)) {
|
|
393
490
|
updateConfig({
|
|
394
491
|
...config,
|
|
395
|
-
|
|
396
|
-
...config
|
|
492
|
+
columns: {
|
|
493
|
+
...config.columns,
|
|
397
494
|
[subsection]: {
|
|
398
|
-
...config[
|
|
495
|
+
...config.columns[subsection],
|
|
399
496
|
[fieldName]: newValue
|
|
400
497
|
}
|
|
401
498
|
}
|
|
@@ -403,6 +500,8 @@ const EditorPanel = () => {
|
|
|
403
500
|
return
|
|
404
501
|
}
|
|
405
502
|
if (null === section && null === subsection) {
|
|
503
|
+
// special case that allows for updating the config object directly
|
|
504
|
+
if (!truthy(fieldName)) console.error('fieldName is required')
|
|
406
505
|
let updatedConfig = { ...config, [fieldName]: newValue }
|
|
407
506
|
enforceRestrictions(updatedConfig)
|
|
408
507
|
updateConfig(updatedConfig)
|
|
@@ -413,13 +512,13 @@ const EditorPanel = () => {
|
|
|
413
512
|
|
|
414
513
|
let sectionValue = isArray ? [...config[section], newValue] : { ...config[section], [fieldName]: newValue }
|
|
415
514
|
|
|
416
|
-
if (
|
|
515
|
+
if (truthy(subsection)) {
|
|
417
516
|
if (isArray) {
|
|
418
517
|
sectionValue = [...config[section]]
|
|
419
518
|
sectionValue[subsection] = { ...sectionValue[subsection], [fieldName]: newValue }
|
|
420
519
|
} else if (typeof newValue === 'string') {
|
|
421
520
|
sectionValue[subsection] = newValue
|
|
422
|
-
} else {
|
|
521
|
+
} else if (truthy(fieldName)) {
|
|
423
522
|
sectionValue = { ...config[section], [subsection]: { ...config[section][subsection], [fieldName]: newValue } }
|
|
424
523
|
}
|
|
425
524
|
}
|
|
@@ -457,30 +556,6 @@ const EditorPanel = () => {
|
|
|
457
556
|
})
|
|
458
557
|
}
|
|
459
558
|
|
|
460
|
-
const removeFilter = index => {
|
|
461
|
-
let filters = [...config.filters]
|
|
462
|
-
|
|
463
|
-
filters.splice(index, 1)
|
|
464
|
-
|
|
465
|
-
updateConfig({ ...config, filters })
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
const updateFilterProp = (name, index, value) => {
|
|
469
|
-
let filters = [...config.filters]
|
|
470
|
-
|
|
471
|
-
filters[index][name] = value
|
|
472
|
-
|
|
473
|
-
updateConfig({ ...config, filters })
|
|
474
|
-
}
|
|
475
|
-
|
|
476
|
-
const addNewFilter = () => {
|
|
477
|
-
let filters = config.filters ? [...config.filters] : []
|
|
478
|
-
|
|
479
|
-
filters.push({ values: [] })
|
|
480
|
-
|
|
481
|
-
updateConfig({ ...config, filters })
|
|
482
|
-
}
|
|
483
|
-
|
|
484
559
|
const addNewSeries = seriesKey => {
|
|
485
560
|
let newSeries = config.series ? [...config.series] : []
|
|
486
561
|
let forecastingStages = Array.from(new Set(data.map(item => item[seriesKey])))
|
|
@@ -505,37 +580,6 @@ const EditorPanel = () => {
|
|
|
505
580
|
updateConfig({ ...config }, newData)
|
|
506
581
|
}
|
|
507
582
|
|
|
508
|
-
const removeSeries = seriesKey => {
|
|
509
|
-
let series = [...config.series]
|
|
510
|
-
let seriesIndex = -1
|
|
511
|
-
|
|
512
|
-
for (let i = 0; i < series.length; i++) {
|
|
513
|
-
if (series[i].dataKey === seriesKey) {
|
|
514
|
-
seriesIndex = i
|
|
515
|
-
break
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
if (seriesIndex !== -1) {
|
|
520
|
-
series.splice(seriesIndex, 1)
|
|
521
|
-
|
|
522
|
-
let newConfig = { ...config, series }
|
|
523
|
-
|
|
524
|
-
if (series.length === 0) {
|
|
525
|
-
delete newConfig.series
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
updateConfig(newConfig)
|
|
529
|
-
}
|
|
530
|
-
|
|
531
|
-
if (config.visualizationType === 'Paired Bar') {
|
|
532
|
-
updateConfig({
|
|
533
|
-
...config,
|
|
534
|
-
series: []
|
|
535
|
-
})
|
|
536
|
-
}
|
|
537
|
-
}
|
|
538
|
-
|
|
539
583
|
const addNewExclusion = exclusionKey => {
|
|
540
584
|
let newExclusion = [...config.exclusions.keys]
|
|
541
585
|
newExclusion.push(exclusionKey)
|
|
@@ -569,16 +613,6 @@ const EditorPanel = () => {
|
|
|
569
613
|
}
|
|
570
614
|
}
|
|
571
615
|
|
|
572
|
-
const getFilters = () => {
|
|
573
|
-
let columns = {}
|
|
574
|
-
|
|
575
|
-
unfilteredData.forEach(row => {
|
|
576
|
-
Object.keys(row).forEach(columnName => (columns[columnName] = true))
|
|
577
|
-
})
|
|
578
|
-
|
|
579
|
-
return Object.keys(columns)
|
|
580
|
-
}
|
|
581
|
-
|
|
582
616
|
const getColumns = (filter = true) => {
|
|
583
617
|
let columns = {}
|
|
584
618
|
unfilteredData.forEach(row => {
|
|
@@ -902,40 +936,8 @@ const EditorPanel = () => {
|
|
|
902
936
|
})
|
|
903
937
|
}
|
|
904
938
|
|
|
905
|
-
// prevents adding duplicates
|
|
906
|
-
const additionalColumns = Object.keys(config.columns).filter(value => {
|
|
907
|
-
const defaultCols = [config.xAxis.dataKey] // ['geo', 'navigate', 'primary', 'latitude', 'longitude']
|
|
908
|
-
|
|
909
|
-
if (true === defaultCols.includes(value)) {
|
|
910
|
-
return false
|
|
911
|
-
}
|
|
912
|
-
return true
|
|
913
|
-
})
|
|
914
|
-
|
|
915
|
-
// just adds a new column but not set to any data yet
|
|
916
|
-
const addAdditionalColumn = number => {
|
|
917
|
-
const columnKey = `additionalColumn${number}`
|
|
918
|
-
|
|
919
|
-
updateConfig({
|
|
920
|
-
...config,
|
|
921
|
-
columns: {
|
|
922
|
-
...config.columns,
|
|
923
|
-
[columnKey]: {
|
|
924
|
-
label: 'New Column',
|
|
925
|
-
dataTable: false,
|
|
926
|
-
tooltips: false,
|
|
927
|
-
prefix: '',
|
|
928
|
-
suffix: '',
|
|
929
|
-
forestPlot: false,
|
|
930
|
-
startingPoint: '0',
|
|
931
|
-
forestPlotAlignRight: false
|
|
932
|
-
}
|
|
933
|
-
}
|
|
934
|
-
})
|
|
935
|
-
}
|
|
936
|
-
|
|
937
939
|
const removeAdditionalColumn = columnName => {
|
|
938
|
-
const newColumns = config.columns
|
|
940
|
+
const newColumns = _.cloneDeep(config.columns)
|
|
939
941
|
|
|
940
942
|
delete newColumns[columnName]
|
|
941
943
|
|
|
@@ -1210,7 +1212,23 @@ const EditorPanel = () => {
|
|
|
1210
1212
|
</>
|
|
1211
1213
|
)}
|
|
1212
1214
|
<span className='divider-heading'>Number Formatting</span>
|
|
1213
|
-
<CheckBox
|
|
1215
|
+
<CheckBox
|
|
1216
|
+
value={config.dataFormat.commas}
|
|
1217
|
+
section='dataFormat'
|
|
1218
|
+
fieldName='commas'
|
|
1219
|
+
label='Add commas'
|
|
1220
|
+
updateField={updateField}
|
|
1221
|
+
tooltip={
|
|
1222
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
1223
|
+
<Tooltip.Target>
|
|
1224
|
+
<Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
|
|
1225
|
+
</Tooltip.Target>
|
|
1226
|
+
<Tooltip.Content>
|
|
1227
|
+
<p>{`Selecting this option will add commas to the left value axis, tooltip hover, and data table.`}</p>
|
|
1228
|
+
</Tooltip.Content>
|
|
1229
|
+
</Tooltip>
|
|
1230
|
+
}
|
|
1231
|
+
/>
|
|
1214
1232
|
<CheckBox
|
|
1215
1233
|
value={config.dataFormat.abbreviated}
|
|
1216
1234
|
section='dataFormat'
|
|
@@ -1943,7 +1961,7 @@ const EditorPanel = () => {
|
|
|
1943
1961
|
{visSupportsDateCategoryNumTicks() && (config.xAxis.type === 'date-time' || !config.xAxis.manual) && (
|
|
1944
1962
|
<TextField value={config.xAxis.numTicks} placeholder='Auto' type='number' min={1} section='xAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
|
|
1945
1963
|
)}
|
|
1946
|
-
{visSupportsDateCategoryHeight() && <TextField value={config.xAxis.
|
|
1964
|
+
{visSupportsDateCategoryHeight() && <TextField value={config.xAxis.padding} type='number' min={0} section='xAxis' fieldName='padding' label={config.orientation === 'horizontal' ? 'Size (Width)' : 'Size (Height)'} className='number-narrow' updateField={updateField} />}
|
|
1947
1965
|
|
|
1948
1966
|
{/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
|
|
1949
1967
|
{/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
|
|
@@ -1992,6 +2010,40 @@ const EditorPanel = () => {
|
|
|
1992
2010
|
{visSupportsDateCategoryAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
|
|
1993
2011
|
</>
|
|
1994
2012
|
)}
|
|
2013
|
+
<CheckBox
|
|
2014
|
+
tooltip={
|
|
2015
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2016
|
+
<Tooltip.Target>
|
|
2017
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2018
|
+
</Tooltip.Target>
|
|
2019
|
+
<Tooltip.Content>
|
|
2020
|
+
<p>Selecting this option will display a "thin line" slightly above the Date/Category Axis to indicate "suppressed data" where "suppressed data" values are indicated in the Data Series.</p>
|
|
2021
|
+
</Tooltip.Content>
|
|
2022
|
+
</Tooltip>
|
|
2023
|
+
}
|
|
2024
|
+
value={config.xAxis.showSuppressedLine}
|
|
2025
|
+
section='xAxis'
|
|
2026
|
+
fieldName='showSuppressedLine'
|
|
2027
|
+
label='Display suppressed data line'
|
|
2028
|
+
updateField={updateField}
|
|
2029
|
+
/>
|
|
2030
|
+
<CheckBox
|
|
2031
|
+
tooltip={
|
|
2032
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2033
|
+
<Tooltip.Target>
|
|
2034
|
+
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2035
|
+
</Tooltip.Target>
|
|
2036
|
+
<Tooltip.Content>
|
|
2037
|
+
<p>Selecting this option will display "suppressed data symbol" on the Date/Category Axis where suppressed data values are indicated in the Data Series, unless a different symbol was chosen from the data series (e.g., suppression symbol) menu.</p>
|
|
2038
|
+
</Tooltip.Content>
|
|
2039
|
+
</Tooltip>
|
|
2040
|
+
}
|
|
2041
|
+
value={config.xAxis.showSuppressedSymbol}
|
|
2042
|
+
section='xAxis'
|
|
2043
|
+
fieldName='showSuppressedSymbol'
|
|
2044
|
+
label='Display suppressed data symbol'
|
|
2045
|
+
updateField={updateField}
|
|
2046
|
+
/>
|
|
1995
2047
|
|
|
1996
2048
|
{config.series?.length === 1 && config.visualizationType === 'Bar' && (
|
|
1997
2049
|
<>
|
|
@@ -2338,6 +2390,7 @@ const EditorPanel = () => {
|
|
|
2338
2390
|
</AccordionItem>
|
|
2339
2391
|
)}
|
|
2340
2392
|
<Panels.Regions name='Regions' />
|
|
2393
|
+
|
|
2341
2394
|
{/* Columns */}
|
|
2342
2395
|
{config.visualizationType !== 'Box Plot' && (
|
|
2343
2396
|
<AccordionItem>
|
|
@@ -2345,235 +2398,7 @@ const EditorPanel = () => {
|
|
|
2345
2398
|
<AccordionItemButton>Columns</AccordionItemButton>
|
|
2346
2399
|
</AccordionItemHeading>
|
|
2347
2400
|
<AccordionItemPanel>
|
|
2348
|
-
{
|
|
2349
|
-
<fieldset className='primary-fieldset edit-block'>
|
|
2350
|
-
<label>
|
|
2351
|
-
<span className='edit-label'>
|
|
2352
|
-
Additional Columns
|
|
2353
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2354
|
-
<Tooltip.Target>
|
|
2355
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2356
|
-
</Tooltip.Target>
|
|
2357
|
-
<Tooltip.Content>
|
|
2358
|
-
<p>You can specify additional columns to display in tooltips and / or the supporting data table.</p>
|
|
2359
|
-
</Tooltip.Content>
|
|
2360
|
-
</Tooltip>
|
|
2361
|
-
</span>
|
|
2362
|
-
</label>
|
|
2363
|
-
{additionalColumns.map(val => (
|
|
2364
|
-
<fieldset className='edit-block' key={val}>
|
|
2365
|
-
<button
|
|
2366
|
-
className='remove-column'
|
|
2367
|
-
onClick={event => {
|
|
2368
|
-
event.preventDefault()
|
|
2369
|
-
removeAdditionalColumn(val)
|
|
2370
|
-
}}
|
|
2371
|
-
>
|
|
2372
|
-
Remove
|
|
2373
|
-
</button>
|
|
2374
|
-
<label>
|
|
2375
|
-
<span className='edit-label column-heading'>Column</span>
|
|
2376
|
-
<select
|
|
2377
|
-
value={config.columns[val] ? config.columns[val].name : getColumns()[0]}
|
|
2378
|
-
onChange={event => {
|
|
2379
|
-
editColumn(val, 'name', event.target.value)
|
|
2380
|
-
}}
|
|
2381
|
-
>
|
|
2382
|
-
{getColumns().map(option => (
|
|
2383
|
-
<option>{option}</option>
|
|
2384
|
-
))}
|
|
2385
|
-
</select>
|
|
2386
|
-
</label>
|
|
2387
|
-
<label>
|
|
2388
|
-
<span className='edit-label column-heading'>Associate to Series</span>
|
|
2389
|
-
<select
|
|
2390
|
-
value={config.columns[val] ? config.columns[val].series : ''}
|
|
2391
|
-
onChange={event => {
|
|
2392
|
-
editColumn(val, 'series', event.target.value)
|
|
2393
|
-
}}
|
|
2394
|
-
>
|
|
2395
|
-
<option value=''>Select series</option>
|
|
2396
|
-
{config.series.map(series => (
|
|
2397
|
-
<option>{series.dataKey}</option>
|
|
2398
|
-
))}
|
|
2399
|
-
</select>
|
|
2400
|
-
</label>
|
|
2401
|
-
<TextField value={config.columns[val].label} section='columns' subsection={val} fieldName='label' label='Label' updateField={updateField} />
|
|
2402
|
-
<ul className='column-edit'>
|
|
2403
|
-
<li className='three-col'>
|
|
2404
|
-
<TextField value={config.columns[val].prefix} section='columns' subsection={val} fieldName='prefix' label='Prefix' updateField={updateField} />
|
|
2405
|
-
<TextField value={config.columns[val].suffix} section='columns' subsection={val} fieldName='suffix' label='Suffix' updateField={updateField} />
|
|
2406
|
-
<TextField type='number' value={config.columns[val].roundToPlace} section='columns' subsection={val} fieldName='roundToPlace' label='Round' updateField={updateField} />
|
|
2407
|
-
</li>
|
|
2408
|
-
<li>
|
|
2409
|
-
<label className='checkbox'>
|
|
2410
|
-
<input
|
|
2411
|
-
type='checkbox'
|
|
2412
|
-
checked={config.columns[val].commas}
|
|
2413
|
-
onChange={event => {
|
|
2414
|
-
editColumn(val, 'commas', event.target.checked)
|
|
2415
|
-
}}
|
|
2416
|
-
/>
|
|
2417
|
-
<span className='edit-label'>Add Commas to Numbers</span>
|
|
2418
|
-
</label>
|
|
2419
|
-
</li>
|
|
2420
|
-
<li>
|
|
2421
|
-
{config.table.showVertical && (
|
|
2422
|
-
<label className='checkbox'>
|
|
2423
|
-
<input
|
|
2424
|
-
type='checkbox'
|
|
2425
|
-
checked={config.columns[val].dataTable}
|
|
2426
|
-
onChange={event => {
|
|
2427
|
-
editColumn(val, 'dataTable', event.target.checked)
|
|
2428
|
-
}}
|
|
2429
|
-
/>
|
|
2430
|
-
<span className='edit-label'>Show in Data Table</span>
|
|
2431
|
-
</label>
|
|
2432
|
-
)}
|
|
2433
|
-
</li>
|
|
2434
|
-
{config.visualizationType === 'Pie' && (
|
|
2435
|
-
<li>
|
|
2436
|
-
<label className='checkbox'>
|
|
2437
|
-
<input
|
|
2438
|
-
type='checkbox'
|
|
2439
|
-
checked={config.columns[val].showInViz}
|
|
2440
|
-
onChange={event => {
|
|
2441
|
-
editColumn(val, 'showInViz', event.target.checked)
|
|
2442
|
-
}}
|
|
2443
|
-
/>
|
|
2444
|
-
<span className='edit-label'>Show in Visualization</span>
|
|
2445
|
-
</label>
|
|
2446
|
-
</li>
|
|
2447
|
-
)}
|
|
2448
|
-
|
|
2449
|
-
{/* disable for now */}
|
|
2450
|
-
|
|
2451
|
-
<li>
|
|
2452
|
-
<label className='checkbox'>
|
|
2453
|
-
<input
|
|
2454
|
-
type='checkbox'
|
|
2455
|
-
checked={config.columns[val].tooltips || false}
|
|
2456
|
-
onChange={event => {
|
|
2457
|
-
updateSeriesTooltip(val, event.target.checked)
|
|
2458
|
-
}}
|
|
2459
|
-
/>
|
|
2460
|
-
<span className='edit-label'>Show in tooltip</span>
|
|
2461
|
-
</label>
|
|
2462
|
-
</li>
|
|
2463
|
-
|
|
2464
|
-
{config.visualizationType === 'Forest Plot' && (
|
|
2465
|
-
<>
|
|
2466
|
-
<li>
|
|
2467
|
-
<label className='checkbox'>
|
|
2468
|
-
<input
|
|
2469
|
-
type='checkbox'
|
|
2470
|
-
checked={config.columns[val].forestPlot || false}
|
|
2471
|
-
onChange={event => {
|
|
2472
|
-
editColumn(val, 'forestPlot', event.target.checked)
|
|
2473
|
-
}}
|
|
2474
|
-
/>
|
|
2475
|
-
<span className='edit-label'>Show in Forest Plot</span>
|
|
2476
|
-
</label>
|
|
2477
|
-
</li>
|
|
2478
|
-
<li>
|
|
2479
|
-
<label className='checkbox'>
|
|
2480
|
-
<input
|
|
2481
|
-
type='checkbox'
|
|
2482
|
-
checked={config.columns[val].forestPlotAlignRight || false}
|
|
2483
|
-
onChange={event => {
|
|
2484
|
-
editColumn(val, 'forestPlotAlignRight', event.target.checked)
|
|
2485
|
-
}}
|
|
2486
|
-
/>
|
|
2487
|
-
<span className='edit-label'>Align Right</span>
|
|
2488
|
-
</label>
|
|
2489
|
-
</li>
|
|
2490
|
-
|
|
2491
|
-
{!config.columns[val].forestPlotAlignRight && (
|
|
2492
|
-
<li>
|
|
2493
|
-
<label className='text'>
|
|
2494
|
-
<span className='edit-label'>Forest Plot Starting Point</span>
|
|
2495
|
-
<input
|
|
2496
|
-
type='number'
|
|
2497
|
-
value={config.columns[val].forestPlotStartingPoint || 0}
|
|
2498
|
-
onChange={event => {
|
|
2499
|
-
editColumn(val, 'forestPlotStartingPoint', event.target.value)
|
|
2500
|
-
}}
|
|
2501
|
-
/>
|
|
2502
|
-
</label>
|
|
2503
|
-
</li>
|
|
2504
|
-
)}
|
|
2505
|
-
</>
|
|
2506
|
-
)}
|
|
2507
|
-
</ul>
|
|
2508
|
-
</fieldset>
|
|
2509
|
-
))}
|
|
2510
|
-
<button
|
|
2511
|
-
className={'btn full-width'}
|
|
2512
|
-
onClick={event => {
|
|
2513
|
-
event.preventDefault()
|
|
2514
|
-
addAdditionalColumn(additionalColumns.length + 1)
|
|
2515
|
-
}}
|
|
2516
|
-
>
|
|
2517
|
-
Add Column
|
|
2518
|
-
</button>
|
|
2519
|
-
</fieldset>
|
|
2520
|
-
)}
|
|
2521
|
-
{'category' === config.legend.type && (
|
|
2522
|
-
<fieldset className='primary-fieldset edit-block'>
|
|
2523
|
-
<label>
|
|
2524
|
-
<span className='edit-label'>
|
|
2525
|
-
Additional Category
|
|
2526
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2527
|
-
<Tooltip.Target>
|
|
2528
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2529
|
-
</Tooltip.Target>
|
|
2530
|
-
<Tooltip.Content>
|
|
2531
|
-
<p>You can provide additional categories to ensure they appear in the legend</p>
|
|
2532
|
-
</Tooltip.Content>
|
|
2533
|
-
</Tooltip>
|
|
2534
|
-
</span>
|
|
2535
|
-
</label>
|
|
2536
|
-
{config.legend.additionalCategories &&
|
|
2537
|
-
config.legend.additionalCategories.map((val, i) => (
|
|
2538
|
-
<fieldset className='edit-block' key={val}>
|
|
2539
|
-
<button
|
|
2540
|
-
className='remove-column'
|
|
2541
|
-
onClick={event => {
|
|
2542
|
-
event.preventDefault()
|
|
2543
|
-
const updatedAdditionaCategories = [...config.legend.additionalCategories]
|
|
2544
|
-
updatedAdditionaCategories.splice(i, 1)
|
|
2545
|
-
updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
|
|
2546
|
-
}}
|
|
2547
|
-
>
|
|
2548
|
-
Remove
|
|
2549
|
-
</button>
|
|
2550
|
-
<TextField
|
|
2551
|
-
value={val}
|
|
2552
|
-
label='Category'
|
|
2553
|
-
section='legend'
|
|
2554
|
-
subsection={null}
|
|
2555
|
-
fieldName='additionalCategories'
|
|
2556
|
-
updateField={(section, subsection, fieldName, value) => {
|
|
2557
|
-
const updatedAdditionaCategories = [...config.legend.additionalCategories]
|
|
2558
|
-
updatedAdditionaCategories[i] = value
|
|
2559
|
-
updateField(section, subsection, fieldName, updatedAdditionaCategories)
|
|
2560
|
-
}}
|
|
2561
|
-
/>
|
|
2562
|
-
</fieldset>
|
|
2563
|
-
))}
|
|
2564
|
-
<button
|
|
2565
|
-
className={'btn full-width'}
|
|
2566
|
-
onClick={event => {
|
|
2567
|
-
event.preventDefault()
|
|
2568
|
-
const updatedAdditionaCategories = [...(config.legend.additionalCategories || [])]
|
|
2569
|
-
updatedAdditionaCategories.push('')
|
|
2570
|
-
updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
|
|
2571
|
-
}}
|
|
2572
|
-
>
|
|
2573
|
-
Add Category
|
|
2574
|
-
</button>
|
|
2575
|
-
</fieldset>
|
|
2576
|
-
)}
|
|
2401
|
+
<ColumnsEditor config={config} updateField={updateField} deleteColumn={removeAdditionalColumn} />{' '}
|
|
2577
2402
|
</AccordionItemPanel>
|
|
2578
2403
|
</AccordionItem>
|
|
2579
2404
|
)}
|
|
@@ -2613,6 +2438,23 @@ const EditorPanel = () => {
|
|
|
2613
2438
|
</Tooltip>
|
|
2614
2439
|
}
|
|
2615
2440
|
/>
|
|
2441
|
+
<CheckBox
|
|
2442
|
+
value={config.legend.hideSuppressedLabels}
|
|
2443
|
+
section='legend'
|
|
2444
|
+
fieldName='hideSuppressedLabels'
|
|
2445
|
+
label='Hide Suppressed Labels'
|
|
2446
|
+
updateField={updateField}
|
|
2447
|
+
tooltip={
|
|
2448
|
+
<Tooltip style={{ textTransform: 'none' }}>
|
|
2449
|
+
<Tooltip.Target>
|
|
2450
|
+
<Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
|
|
2451
|
+
</Tooltip.Target>
|
|
2452
|
+
<Tooltip.Content>
|
|
2453
|
+
<p>Hiding suppressed labels will not override the 'Special Class' assigned to line chart indicating "suppressed" data in the Data Series Panel.</p>
|
|
2454
|
+
</Tooltip.Content>
|
|
2455
|
+
</Tooltip>
|
|
2456
|
+
}
|
|
2457
|
+
/>
|
|
2616
2458
|
{/* {config.visualizationType === 'Box Plot' &&
|
|
2617
2459
|
<>
|
|
2618
2460
|
<CheckBox value={config.boxplot.legend.displayHowToReadText} fieldName='displayHowToReadText' section='boxplot' subsection='legend' label='Display How To Read Text' updateField={updateField} />
|
|
@@ -2714,161 +2556,7 @@ const EditorPanel = () => {
|
|
|
2714
2556
|
<AccordionItemButton>Filters</AccordionItemButton>
|
|
2715
2557
|
</AccordionItemHeading>
|
|
2716
2558
|
<AccordionItemPanel>
|
|
2717
|
-
{config
|
|
2718
|
-
<>
|
|
2719
|
-
{/* prettier-ignore */}
|
|
2720
|
-
<Select
|
|
2721
|
-
value={config.filterBehavior}
|
|
2722
|
-
fieldName='filterBehavior'
|
|
2723
|
-
label='Filter Behavior'
|
|
2724
|
-
updateField={updateField}
|
|
2725
|
-
options={['Apply Button', 'Filter Change']}
|
|
2726
|
-
tooltip={
|
|
2727
|
-
<Tooltip style={{ textTransform: 'none' }}>
|
|
2728
|
-
<Tooltip.Target>
|
|
2729
|
-
<Icon display='question' style={{ marginLeft: '0.5rem' }} />
|
|
2730
|
-
</Tooltip.Target>
|
|
2731
|
-
<Tooltip.Content>
|
|
2732
|
-
<p>The Apply Button option changes the visualization when the user clicks "apply". The Filter Change option immediately changes the visualization when the selection is changed.</p>
|
|
2733
|
-
</Tooltip.Content>
|
|
2734
|
-
</Tooltip>
|
|
2735
|
-
}
|
|
2736
|
-
/>
|
|
2737
|
-
<br />
|
|
2738
|
-
</>
|
|
2739
|
-
)}
|
|
2740
|
-
{config.filters && (
|
|
2741
|
-
<ul className='filters-list'>
|
|
2742
|
-
{/* Whether filters should apply onChange or Apply Button */}
|
|
2743
|
-
|
|
2744
|
-
{config.filters.map((filter, index) => {
|
|
2745
|
-
if (filter.type === 'url') return <></>
|
|
2746
|
-
|
|
2747
|
-
return (
|
|
2748
|
-
<fieldset className='edit-block' key={index}>
|
|
2749
|
-
<button
|
|
2750
|
-
type='button'
|
|
2751
|
-
className='remove-column'
|
|
2752
|
-
onClick={() => {
|
|
2753
|
-
removeFilter(index)
|
|
2754
|
-
}}
|
|
2755
|
-
>
|
|
2756
|
-
Remove
|
|
2757
|
-
</button>
|
|
2758
|
-
<label>
|
|
2759
|
-
<span className='edit-label column-heading'>Filter</span>
|
|
2760
|
-
<select
|
|
2761
|
-
value={filter.columnName}
|
|
2762
|
-
onChange={e => {
|
|
2763
|
-
updateFilterProp('columnName', index, e.target.value)
|
|
2764
|
-
}}
|
|
2765
|
-
>
|
|
2766
|
-
<option value=''>- Select Option -</option>
|
|
2767
|
-
{getFilters().map((dataKey, index) => (
|
|
2768
|
-
<option value={dataKey} key={index}>
|
|
2769
|
-
{dataKey}
|
|
2770
|
-
</option>
|
|
2771
|
-
))}
|
|
2772
|
-
</select>
|
|
2773
|
-
</label>
|
|
2774
|
-
|
|
2775
|
-
<label>
|
|
2776
|
-
<span className='edit-showDropdown column-heading'>Show Filter Input</span>
|
|
2777
|
-
<input
|
|
2778
|
-
type='checkbox'
|
|
2779
|
-
checked={filter.showDropdown === undefined ? true : filter.showDropdown}
|
|
2780
|
-
onChange={e => {
|
|
2781
|
-
updateFilterProp('showDropdown', index, e.target.checked)
|
|
2782
|
-
}}
|
|
2783
|
-
/>
|
|
2784
|
-
</label>
|
|
2785
|
-
|
|
2786
|
-
<label>
|
|
2787
|
-
<span className='edit-label column-heading'>Filter Style</span>
|
|
2788
|
-
|
|
2789
|
-
<select
|
|
2790
|
-
value={filter.filterStyle}
|
|
2791
|
-
onChange={e => {
|
|
2792
|
-
updateFilterProp('filterStyle', index, e.target.value)
|
|
2793
|
-
}}
|
|
2794
|
-
>
|
|
2795
|
-
{filterStyleOptions.map((item, index) => {
|
|
2796
|
-
return (
|
|
2797
|
-
<option key={`filter-style-${index}`} value={item}>
|
|
2798
|
-
{item}
|
|
2799
|
-
</option>
|
|
2800
|
-
)
|
|
2801
|
-
})}
|
|
2802
|
-
</select>
|
|
2803
|
-
</label>
|
|
2804
|
-
<label>
|
|
2805
|
-
<span className='edit-label column-heading'>Label</span>
|
|
2806
|
-
<input
|
|
2807
|
-
type='text'
|
|
2808
|
-
value={filter.label}
|
|
2809
|
-
onChange={e => {
|
|
2810
|
-
updateFilterProp('label', index, e.target.value)
|
|
2811
|
-
}}
|
|
2812
|
-
/>
|
|
2813
|
-
</label>
|
|
2814
|
-
|
|
2815
|
-
<label>
|
|
2816
|
-
<span className='edit-label column-heading'>Default Value Set By Query String Parameter</span>
|
|
2817
|
-
<input
|
|
2818
|
-
type='text'
|
|
2819
|
-
value={filter.setByQueryParameter}
|
|
2820
|
-
onChange={e => {
|
|
2821
|
-
updateFilterProp('setByQueryParameter', index, e.target.value)
|
|
2822
|
-
}}
|
|
2823
|
-
/>
|
|
2824
|
-
</label>
|
|
2825
|
-
|
|
2826
|
-
<label>
|
|
2827
|
-
<span className='edit-filterOrder column-heading'>Filter Order</span>
|
|
2828
|
-
<select value={filter.order ? filter.order : 'asc'} onChange={e => updateFilterProp('order', index, e.target.value)}>
|
|
2829
|
-
{filterOrderOptions.map((option, index) => {
|
|
2830
|
-
return (
|
|
2831
|
-
<option value={option.value} key={`filter-${index}`}>
|
|
2832
|
-
{option.label}
|
|
2833
|
-
</option>
|
|
2834
|
-
)
|
|
2835
|
-
})}
|
|
2836
|
-
</select>
|
|
2837
|
-
|
|
2838
|
-
{filter.order === 'cust' && (
|
|
2839
|
-
<DragDropContext onDragEnd={({ source, destination }) => handleFilterOrder(source.index, destination.index, index, config.filters[index])}>
|
|
2840
|
-
<Droppable droppableId='filter_order'>
|
|
2841
|
-
{provided => (
|
|
2842
|
-
<ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
|
|
2843
|
-
{config.filters[index]?.values.map((value, index) => {
|
|
2844
|
-
return (
|
|
2845
|
-
<Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
|
|
2846
|
-
{(provided, snapshot) => (
|
|
2847
|
-
<li>
|
|
2848
|
-
<div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
|
|
2849
|
-
{value}
|
|
2850
|
-
</div>
|
|
2851
|
-
</li>
|
|
2852
|
-
)}
|
|
2853
|
-
</Draggable>
|
|
2854
|
-
)
|
|
2855
|
-
})}
|
|
2856
|
-
{provided.placeholder}
|
|
2857
|
-
</ul>
|
|
2858
|
-
)}
|
|
2859
|
-
</Droppable>
|
|
2860
|
-
</DragDropContext>
|
|
2861
|
-
)}
|
|
2862
|
-
</label>
|
|
2863
|
-
</fieldset>
|
|
2864
|
-
)
|
|
2865
|
-
})}
|
|
2866
|
-
</ul>
|
|
2867
|
-
)}
|
|
2868
|
-
{!config.filters && <p style={{ textAlign: 'center' }}>There are currently no filters.</p>}
|
|
2869
|
-
<button type='button' onClick={addNewFilter} className='btn full-width'>
|
|
2870
|
-
Add Filter
|
|
2871
|
-
</button>
|
|
2559
|
+
<VizFilterEditor config={config} updateField={updateField} rawData={rawData} />
|
|
2872
2560
|
</AccordionItemPanel>
|
|
2873
2561
|
</AccordionItem>
|
|
2874
2562
|
)}
|