@cdc/chart 4.24.3 → 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.
Files changed (39) hide show
  1. package/dist/cdcchart.js +34377 -33726
  2. package/examples/feature/line/line-chart.json +361 -37
  3. package/examples/region-issue.json +2065 -0
  4. package/examples/test.json +5409 -0
  5. package/index.html +13 -11
  6. package/package.json +2 -2
  7. package/src/CdcChart.tsx +159 -89
  8. package/src/_stories/Chart.stories.tsx +8 -0
  9. package/src/_stories/_mock/bar-chart-suppressed.json +474 -0
  10. package/src/components/AreaChart/components/AreaChart.jsx +2 -2
  11. package/src/components/BarChart/components/BarChart.Horizontal.tsx +61 -63
  12. package/src/components/BarChart/components/BarChart.Vertical.tsx +79 -94
  13. package/src/components/DeviationBar.jsx +4 -2
  14. package/src/components/EditorPanel/EditorPanel.tsx +1580 -1924
  15. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +19 -2
  16. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +0 -1
  17. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -5
  18. package/src/components/EditorPanel/editor-panel.scss +0 -724
  19. package/src/components/EditorPanel/useEditorPermissions.js +4 -1
  20. package/src/components/Legend/Legend.Component.tsx +82 -58
  21. package/src/components/Legend/Legend.tsx +5 -1
  22. package/src/components/LineChart/LineChartProps.ts +13 -6
  23. package/src/components/LineChart/components/LineChart.Circle.tsx +22 -11
  24. package/src/components/LineChart/helpers.ts +134 -10
  25. package/src/components/LineChart/index.tsx +69 -42
  26. package/src/components/LinearChart.jsx +156 -139
  27. package/src/components/ZoomBrush.tsx +40 -21
  28. package/src/data/initial-state.js +4 -4
  29. package/src/hooks/useBarChart.js +47 -22
  30. package/src/hooks/useMinMax.ts +21 -2
  31. package/src/hooks/useScales.ts +33 -1
  32. package/src/hooks/useTooltip.tsx +11 -11
  33. package/src/scss/main.scss +80 -5
  34. package/src/types/ChartConfig.ts +3 -13
  35. package/src/types/ChartContext.ts +4 -0
  36. package/src/_stories/ChartLine.preliminary.tsx +0 -19
  37. package/src/_stories/ChartSuppress.stories.tsx +0 -19
  38. package/src/_stories/_mock/suppress_mock.json +0 -911
  39. package/src/helpers/computeMarginBottom.ts +0 -56
@@ -1,24 +1,24 @@
1
1
  import { useState, useEffect, useCallback, memo, useContext } from 'react'
2
- import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
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
+ import Layout from '@cdc/core/components/Layout'
5
6
 
6
7
  // @cdc/core
7
8
  import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
8
9
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
9
10
  import Icon from '@cdc/core/components/ui/Icon'
10
- import InputToggle from '@cdc/core/components/inputs/InputToggle'
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'
11
14
  import Tooltip from '@cdc/core/components/ui/Tooltip'
12
15
  import { Select, TextField, CheckBox } from '@cdc/core/components/EditorPanel/Inputs'
13
16
 
14
17
  // chart components
15
18
  import Panels from './components/Panels'
16
- import Series from './components/Panel.Series.jsx'
17
19
 
18
20
  // cdc additional
19
- import { useColorPalette } from '../../hooks/useColorPalette'
20
21
  import { useEditorPermissions } from './useEditorPermissions'
21
- import { useFilters } from '@cdc/core/components/Filters'
22
22
  import { useHighlightedBars } from '../../hooks/useHighlightedBars'
23
23
  import ConfigContext from '../../ConfigContext'
24
24
  import useReduceData from '../../hooks/useReduceData'
@@ -26,113 +26,57 @@ import useRightAxis from '../../hooks/useRightAxis'
26
26
  import WarningImage from '../../images/warning.svg'
27
27
  import useMinMax from '../../hooks/useMinMax'
28
28
 
29
- import { type ChartConfig } from '../../types/ChartConfig'
30
29
  import { type ChartContext } from '../../types/ChartContext'
30
+ import { type ChartConfig } from '../../types/ChartConfig'
31
31
 
32
32
  import './editor-panel.scss'
33
33
  import { Anchor } from '@cdc/core/types/Axis'
34
- import DataTableEditor from '@cdc/core/components/EditorPanel/DataTableEditor'
35
34
  import EditorPanelContext from './EditorPanelContext'
35
+ import _ from 'lodash'
36
+ import { adjustedSymbols as symbolCodes } from '@cdc/core/helpers/footnoteSymbols'
36
37
 
37
- const DataSuppression = memo(({ config, updateConfig, data }: any) => {
38
- const getColumnOptions = () => {
39
- const keys = new Set()
40
- data.forEach(d => {
41
- Object.keys(d).forEach(key => {
42
- keys.add(key)
43
- })
44
- })
45
- return [...keys]
46
- }
47
-
48
- const getIconOptions = () => {
49
- return ['star']
50
- }
51
-
52
- let removeColumn = i => {
53
- let suppressedData = []
54
-
55
- if (config.suppressedData) {
56
- suppressedData = [...config.suppressedData]
57
- }
58
-
59
- suppressedData.splice(i, 1)
38
+ interface PreliminaryProps {
39
+ config: ChartConfig
40
+ updateConfig: Function
41
+ data: Record<string, any>[]
42
+ }
60
43
 
61
- updateConfig({ ...config, suppressedData })
62
- }
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
63
50
 
64
- let addColumn = () => {
65
- let suppressedData = config.suppressedData ? [...config.suppressedData] : []
66
- suppressedData.push({ label: '', column: '', value: '', icon: '' })
67
- updateConfig({ ...config, suppressedData })
51
+ const getColumnOptions = () => {
52
+ return _.uniq(_.flatMap(data, _.keys))
68
53
  }
69
54
 
70
- let update = (fieldName, value, i) => {
71
- let suppressedData = []
72
-
73
- if (config.suppressedData) {
74
- suppressedData = [...config.suppressedData]
75
- }
76
-
77
- suppressedData[i][fieldName] = value
78
- updateConfig({ ...config, suppressedData })
55
+ const getTypeOptions = () => {
56
+ return config.visualizationType === 'Line' || hasComboLineSeries ? ['effect', 'suppression'] : ['suppression']
79
57
  }
80
58
 
81
- return (
82
- <>
83
- {config.suppressedData &&
84
- config.suppressedData.map(({ label, column, value, icon }, i) => {
85
- return (
86
- <div key={`suppressed-${i}`} className='edit-block'>
87
- <button
88
- type='button'
89
- className='remove-column'
90
- onClick={event => {
91
- event.preventDefault()
92
- removeColumn(i)
93
- }}
94
- >
95
- Remove
96
- </button>
97
- <Select value={column} initial='Select' fieldName='column' label='Column' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} options={getColumnOptions()} />
98
- <TextField value={value} fieldName='value' label='Value' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} />
99
- <Select value={icon} initial='Select' fieldName='icon' label='Icon' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} options={getIconOptions()} />
100
- <TextField value={label} fieldName='label' label='Label' placeholder='suppressed' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} />
101
- </div>
102
- )
103
- })}
104
-
105
- <button type='button' onClick={addColumn} className='btn full-width'>
106
- Add Suppression Class
107
- </button>
108
- </>
109
- )
110
- })
111
- const PreliminaryData = memo(({ config, updateConfig, data }) => {
112
- const getColumnOptions = () => {
113
- const keys = new Set()
114
- data.forEach(d => {
115
- Object.keys(d).forEach(key => {
116
- keys.add(key)
117
- })
118
- })
119
- 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'
120
64
  }
121
65
 
122
- const getTypeOptions = () => {
123
- if (config.visualizationType === 'Line' || config.visualizationType === 'Combo') {
124
- return ['effect']
125
- } else {
126
- return ['suppression']
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
+ }
127
74
  }
128
75
  }
129
76
 
130
- const getStyleOptions = () => {
131
- if (config.visualizationType === 'Line' || config.visualizationType === 'Combo') {
132
- return ['Dashed Small', 'Dashed Medium', 'Dashed Large', 'Open Circles']
133
- }
134
- if (config.visualizationType === 'Bar') {
135
- return ['star']
77
+ const getSymbolOptions = () => {
78
+ if (config.visualizationType === 'Bar' || hasComboBarSeries) {
79
+ return Object.keys(symbolCodes)
136
80
  }
137
81
  }
138
82
 
@@ -149,8 +93,23 @@ const PreliminaryData = memo(({ config, updateConfig, data }) => {
149
93
  }
150
94
 
151
95
  let addColumn = () => {
96
+ const defaultType = config.visualizationType === 'Line' ? 'effect' : 'suppression'
152
97
  let preliminaryData = config.preliminaryData ? [...config.preliminaryData] : []
153
- preliminaryData.push({ type: '', label: '', column: '', value: '', style: '' })
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)
154
113
  updateConfig({ ...config, preliminaryData })
155
114
  }
156
115
 
@@ -162,15 +121,22 @@ const PreliminaryData = memo(({ config, updateConfig, data }) => {
162
121
  }
163
122
 
164
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
+ }
165
130
  updateConfig({ ...config, preliminaryData })
166
131
  }
167
132
 
168
133
  return (
169
134
  <>
170
135
  {config.preliminaryData &&
171
- config.preliminaryData.map(({ seriesKey, type, label, column, value, style }, i) => {
136
+ config.preliminaryData?.map(({ column, displayLegend, displayTable, displayTooltip, label, seriesKey, style, symbol, type, value }, i) => {
172
137
  return (
173
138
  <div key={`preliminaryData-${i}`} className='edit-block'>
139
+ <p> {type === 'suppression' ? 'Suppressed' : 'Effect'} Data</p>
174
140
  <button
175
141
  type='button'
176
142
  className='remove-column'
@@ -181,23 +147,156 @@ const PreliminaryData = memo(({ config, updateConfig, data }) => {
181
147
  >
182
148
  Remove
183
149
  </button>
184
- <Select value={type} initial='Select' fieldName='type' label='Type' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} options={getTypeOptions()} />
185
- <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} />
186
- <Select value={column} initial='Select' fieldName='column' label='COLUMN WITH CONFIGURATION VALUE' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} options={getColumnOptions()} />
187
- <TextField value={value} fieldName='value' label='VALUE TO TRIGGER' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} />
188
- <Select value={style} initial='Select' fieldName='style' label='Style' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} options={getStyleOptions()} />
189
150
 
190
- <TextField value={label} fieldName='label' label='Label' placeholder='' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} />
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
+ )}
191
290
  </div>
192
291
  )
193
292
  })}
194
293
 
195
294
  <button type='button' onClick={addColumn} className='btn full-width'>
196
- {config.visualizationType === 'Line' || config.visualizationType === 'Combo' ? 'Add Special Line' : config.visualizationType === 'Bar' ? ' Add Special Bar' : 'Add Special Line/Bar'}
295
+ {config.visualizationType === 'Line' ? 'Add Special Line' : config.visualizationType === 'Bar' ? ' Add Special Bar' : 'Add Special Bar/Line'}
197
296
  </button>
198
297
  </>
199
298
  )
200
- })
299
+ }
201
300
 
202
301
  const EditorPanel = () => {
203
302
  const {
@@ -223,9 +322,6 @@ const EditorPanel = () => {
223
322
  } = useContext<ChartContext>(ConfigContext)
224
323
 
225
324
  const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
226
-
227
- const { twoColorPalettes, sequential, nonSequential } = useColorPalette(config, updateConfig)
228
-
229
325
  const properties = { data, config }
230
326
  const { leftMax, rightMax } = useMinMax(properties)
231
327
 
@@ -275,9 +371,6 @@ const EditorPanel = () => {
275
371
  visHasDataSuppression
276
372
  } = useEditorPermissions()
277
373
 
278
- // argument acts as props
279
- const { handleFilterOrder, filterOrderOptions, filterStyleOptions } = useFilters({ config, setConfig: updateConfig, filteredData: data, setFilteredData })
280
-
281
374
  // when the visualization type changes we
282
375
  // have to update the individual series type & axis details
283
376
  // dataKey is unchanged here.
@@ -388,13 +481,18 @@ const EditorPanel = () => {
388
481
  return
389
482
  }
390
483
 
391
- if (section === 'columns' && subsection !== '' && fieldName !== '') {
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)) {
392
490
  updateConfig({
393
491
  ...config,
394
- [section]: {
395
- ...config[section],
492
+ columns: {
493
+ ...config.columns,
396
494
  [subsection]: {
397
- ...config[section][subsection],
495
+ ...config.columns[subsection],
398
496
  [fieldName]: newValue
399
497
  }
400
498
  }
@@ -402,6 +500,8 @@ const EditorPanel = () => {
402
500
  return
403
501
  }
404
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')
405
505
  let updatedConfig = { ...config, [fieldName]: newValue }
406
506
  enforceRestrictions(updatedConfig)
407
507
  updateConfig(updatedConfig)
@@ -412,13 +512,13 @@ const EditorPanel = () => {
412
512
 
413
513
  let sectionValue = isArray ? [...config[section], newValue] : { ...config[section], [fieldName]: newValue }
414
514
 
415
- if (null !== subsection) {
515
+ if (truthy(subsection)) {
416
516
  if (isArray) {
417
517
  sectionValue = [...config[section]]
418
518
  sectionValue[subsection] = { ...sectionValue[subsection], [fieldName]: newValue }
419
519
  } else if (typeof newValue === 'string') {
420
520
  sectionValue[subsection] = newValue
421
- } else {
521
+ } else if (truthy(fieldName)) {
422
522
  sectionValue = { ...config[section], [subsection]: { ...config[section][subsection], [fieldName]: newValue } }
423
523
  }
424
524
  }
@@ -456,30 +556,6 @@ const EditorPanel = () => {
456
556
  })
457
557
  }
458
558
 
459
- const removeFilter = index => {
460
- let filters = [...config.filters]
461
-
462
- filters.splice(index, 1)
463
-
464
- updateConfig({ ...config, filters })
465
- }
466
-
467
- const updateFilterProp = (name, index, value) => {
468
- let filters = [...config.filters]
469
-
470
- filters[index][name] = value
471
-
472
- updateConfig({ ...config, filters })
473
- }
474
-
475
- const addNewFilter = () => {
476
- let filters = config.filters ? [...config.filters] : []
477
-
478
- filters.push({ values: [] })
479
-
480
- updateConfig({ ...config, filters })
481
- }
482
-
483
559
  const addNewSeries = seriesKey => {
484
560
  let newSeries = config.series ? [...config.series] : []
485
561
  let forecastingStages = Array.from(new Set(data.map(item => item[seriesKey])))
@@ -504,37 +580,6 @@ const EditorPanel = () => {
504
580
  updateConfig({ ...config }, newData)
505
581
  }
506
582
 
507
- const removeSeries = seriesKey => {
508
- let series = [...config.series]
509
- let seriesIndex = -1
510
-
511
- for (let i = 0; i < series.length; i++) {
512
- if (series[i].dataKey === seriesKey) {
513
- seriesIndex = i
514
- break
515
- }
516
- }
517
-
518
- if (seriesIndex !== -1) {
519
- series.splice(seriesIndex, 1)
520
-
521
- let newConfig = { ...config, series }
522
-
523
- if (series.length === 0) {
524
- delete newConfig.series
525
- }
526
-
527
- updateConfig(newConfig)
528
- }
529
-
530
- if (config.visualizationType === 'Paired Bar') {
531
- updateConfig({
532
- ...config,
533
- series: []
534
- })
535
- }
536
- }
537
-
538
583
  const addNewExclusion = exclusionKey => {
539
584
  let newExclusion = [...config.exclusions.keys]
540
585
  newExclusion.push(exclusionKey)
@@ -568,16 +613,6 @@ const EditorPanel = () => {
568
613
  }
569
614
  }
570
615
 
571
- const getFilters = () => {
572
- let columns = {}
573
-
574
- unfilteredData.forEach(row => {
575
- Object.keys(row).forEach(columnName => (columns[columnName] = true))
576
- })
577
-
578
- return Object.keys(columns)
579
- }
580
-
581
616
  const getColumns = (filter = true) => {
582
617
  let columns = {}
583
618
  unfilteredData.forEach(row => {
@@ -617,40 +652,10 @@ const EditorPanel = () => {
617
652
 
618
653
  const onBackClick = () => {
619
654
  setDisplayPanel(!displayPanel)
620
- }
621
-
622
- const Error = () => {
623
- return (
624
- <section className='waiting'>
625
- <section className='waiting-container'>
626
- <h3>Error With Configuration</h3>
627
- <p>{config.runtime.editorErrorMessage}</p>
628
- </section>
629
- </section>
630
- )
631
- }
632
-
633
- const Confirm = () => {
634
- const confirmDone = e => {
635
- e.preventDefault()
636
-
637
- let newConfig = { ...config }
638
- delete newConfig.newViz
639
-
640
- updateConfig(newConfig)
641
- }
642
-
643
- return (
644
- <section className='waiting'>
645
- <section className='waiting-container'>
646
- <h3>Finish Configuring</h3>
647
- <p>Set all required options to the left and confirm below to display a preview of the chart.</p>
648
- <button className='btn' style={{ margin: '1em auto' }} disabled={missingRequiredSections()} onClick={confirmDone}>
649
- I'm Done
650
- </button>
651
- </section>
652
- </section>
653
- )
655
+ updateConfig({
656
+ ...config,
657
+ showEditorPanel: !displayPanel
658
+ })
654
659
  }
655
660
 
656
661
  const convertStateToConfig = () => {
@@ -931,40 +936,8 @@ const EditorPanel = () => {
931
936
  })
932
937
  }
933
938
 
934
- // prevents adding duplicates
935
- const additionalColumns = Object.keys(config.columns).filter(value => {
936
- const defaultCols = [config.xAxis.dataKey] // ['geo', 'navigate', 'primary', 'latitude', 'longitude']
937
-
938
- if (true === defaultCols.includes(value)) {
939
- return false
940
- }
941
- return true
942
- })
943
-
944
- // just adds a new column but not set to any data yet
945
- const addAdditionalColumn = number => {
946
- const columnKey = `additionalColumn${number}`
947
-
948
- updateConfig({
949
- ...config,
950
- columns: {
951
- ...config.columns,
952
- [columnKey]: {
953
- label: 'New Column',
954
- dataTable: false,
955
- tooltips: false,
956
- prefix: '',
957
- suffix: '',
958
- forestPlot: false,
959
- startingPoint: '0',
960
- forestPlotAlignRight: false
961
- }
962
- }
963
- })
964
- }
965
-
966
939
  const removeAdditionalColumn = columnName => {
967
- const newColumns = config.columns
940
+ const newColumns = _.cloneDeep(config.columns)
968
941
 
969
942
  delete newColumns[columnName]
970
943
 
@@ -1076,128 +1049,144 @@ const EditorPanel = () => {
1076
1049
  return (
1077
1050
  <EditorPanelContext.Provider value={editorContextValues}>
1078
1051
  <ErrorBoundary component='EditorPanel'>
1079
- {config.newViz && <Confirm />}
1080
- {undefined === config.newViz && config.runtime && config.runtime?.editorErrorMessage && <Error />}
1081
- <button className={displayPanel ? `editor-toggle` : `editor-toggle collapsed`} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick}></button>
1082
- <section className={`${displayPanel ? 'editor-panel cove' : 'hidden editor-panel cove'}${isDashboard ? ' dashboard' : ''}`}>
1083
- <div aria-level={2} role='heading' className='heading-2'>
1084
- Configure Chart
1085
- </div>
1086
- <section className='form-container'>
1087
- <Accordion allowZeroExpanded={true}>
1088
- <Panels.General name='General' />
1089
- <Panels.ForestPlot name='Forest Plot Settings' />
1090
- <Panels.Sankey name='Sankey' />
1091
- {config.visualizationType !== 'Pie' && config.visualizationType !== 'Forest Plot' && config.visualizationType !== 'Sankey' && (
1092
- <AccordionItem>
1093
- <AccordionItemHeading>
1094
- <AccordionItemButton>Data Series {(!config.series || config.series.length === 0 || (config.visualizationType === 'Paired Bar' && config.series.length < 2)) && <WarningImage width='25' className='warning-icon' />}</AccordionItemButton>
1095
- </AccordionItemHeading>
1096
- <AccordionItemPanel>
1097
- {(!config.series || config.series.length === 0) && config.visualizationType !== 'Paired Bar' && <p className='warning'>At least one series is required</p>}
1098
- {(!config.series || config.series.length === 0 || config.series.length < 2) && config.visualizationType === 'Paired Bar' && <p className='warning'>Select two data series for paired bar chart (e.g., Male and Female).</p>}
1052
+ <Layout.Sidebar displayPanel={displayPanel} isDashboard={isDashboard} title={'Configure Chart'} onBackClick={onBackClick}>
1053
+ <Accordion allowZeroExpanded={true}>
1054
+ <Panels.General name='General' />
1055
+ <Panels.ForestPlot name='Forest Plot Settings' />
1056
+ <Panels.Sankey name='Sankey' />
1057
+ {config.visualizationType !== 'Pie' && config.visualizationType !== 'Forest Plot' && config.visualizationType !== 'Sankey' && (
1058
+ <AccordionItem>
1059
+ <AccordionItemHeading>
1060
+ <AccordionItemButton>Data Series {(!config.series || config.series.length === 0 || (config.visualizationType === 'Paired Bar' && config.series.length < 2)) && <WarningImage width='25' className='warning-icon' />}</AccordionItemButton>
1061
+ </AccordionItemHeading>
1062
+ <AccordionItemPanel>
1063
+ {(!config.series || config.series.length === 0) && config.visualizationType !== 'Paired Bar' && <p className='warning'>At least one series is required</p>}
1064
+ {(!config.series || config.series.length === 0 || config.series.length < 2) && config.visualizationType === 'Paired Bar' && <p className='warning'>Select two data series for paired bar chart (e.g., Male and Female).</p>}
1065
+ <>
1066
+ <Select
1067
+ fieldName='visualizationType'
1068
+ label='Add Data Series'
1069
+ initial='Select'
1070
+ onChange={e => {
1071
+ if (e.target.value !== '' && e.target.value !== 'Select') {
1072
+ addNewSeries(e.target.value)
1073
+ }
1074
+ e.target.value = ''
1075
+ }}
1076
+ options={getColumns()}
1077
+ />
1078
+ {config.series && config.series.length !== 0 && (
1079
+ <Panels.Series.Wrapper getColumns={getColumns}>
1080
+ <fieldset>
1081
+ <legend className='edit-label float-left'>Displaying</legend>
1082
+ <Tooltip style={{ textTransform: 'none' }}>
1083
+ <Tooltip.Target>
1084
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1085
+ </Tooltip.Target>
1086
+ <Tooltip.Content>
1087
+ <p>A data series is a set of related data points plotted in a chart and typically represented in the chart legend.</p>
1088
+ </Tooltip.Content>
1089
+ </Tooltip>
1090
+ </fieldset>
1091
+
1092
+ <DragDropContext onDragEnd={({ source, destination }) => handleSeriesChange(source.index, destination.index)}>
1093
+ <Droppable droppableId='filter_order'>
1094
+ {/* prettier-ignore */}
1095
+ {provided => {
1096
+ return (
1097
+ <ul {...provided.droppableProps} className='series-list' ref={provided.innerRef}>
1098
+ <Panels.Series.List series={config.series} getItemStyle={getItemStyle} sortableItemStyles={sortableItemStyles} chartsWithOptions={chartsWithOptions} />
1099
+ {provided.placeholder}
1100
+ </ul>
1101
+ )
1102
+ }}
1103
+ </Droppable>
1104
+ </DragDropContext>
1105
+ </Panels.Series.Wrapper>
1106
+ )}
1107
+ </>
1108
+ {config.series && config.series.length <= 1 && config.visualizationType === 'Bar' && (
1099
1109
  <>
1100
- <Select
1101
- fieldName='visualizationType'
1102
- label='Add Data Series'
1103
- initial='Select'
1104
- onChange={e => {
1105
- if (e.target.value !== '' && e.target.value !== 'Select') {
1106
- addNewSeries(e.target.value)
1107
- }
1108
- e.target.value = ''
1109
- }}
1110
- options={getColumns()}
1111
- />
1112
- {config.series && config.series.length !== 0 && (
1113
- <Panels.Series.Wrapper getColumns={getColumns}>
1114
- <fieldset>
1115
- <legend className='edit-label float-left'>Displaying</legend>
1116
- <Tooltip style={{ textTransform: 'none' }}>
1117
- <Tooltip.Target>
1118
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1119
- </Tooltip.Target>
1120
- <Tooltip.Content>
1121
- <p>A data series is a set of related data points plotted in a chart and typically represented in the chart legend.</p>
1122
- </Tooltip.Content>
1123
- </Tooltip>
1124
- </fieldset>
1125
-
1126
- <DragDropContext onDragEnd={({ source, destination }) => handleSeriesChange(source.index, destination.index)}>
1127
- <Droppable droppableId='filter_order'>
1128
- {/* prettier-ignore */}
1129
- {provided => {
1130
- return (
1131
- <ul {...provided.droppableProps} className='series-list' ref={provided.innerRef}>
1132
- <Panels.Series.List series={config.series} getItemStyle={getItemStyle} sortableItemStyles={sortableItemStyles} chartsWithOptions={chartsWithOptions} />
1133
- {provided.placeholder}
1134
- </ul>
1135
- )
1136
- }}
1137
- </Droppable>
1138
- </DragDropContext>
1139
- </Panels.Series.Wrapper>
1140
- )}
1110
+ <span className='divider-heading'>Confidence Keys</span>
1111
+ <Select value={config.confidenceKeys.upper || ''} section='confidenceKeys' fieldName='upper' label='Upper' updateField={updateField} initial='Select' options={getColumns()} />
1112
+ <Select value={config.confidenceKeys.lower || ''} section='confidenceKeys' fieldName='lower' label='Lower' updateField={updateField} initial='Select' options={getColumns()} />
1141
1113
  </>
1142
- {config.series && config.series.length <= 1 && config.visualizationType === 'Bar' && (
1143
- <>
1144
- <span className='divider-heading'>Confidence Keys</span>
1145
- <Select value={config.confidenceKeys.upper || ''} section='confidenceKeys' fieldName='upper' label='Upper' updateField={updateField} initial='Select' options={getColumns()} />
1146
- <Select value={config.confidenceKeys.lower || ''} section='confidenceKeys' fieldName='lower' label='Lower' updateField={updateField} initial='Select' options={getColumns()} />
1147
- </>
1148
- )}
1149
- {visSupportsRankByValue() && config.series && config.series.length === 1 && <Select fieldName='visualizationType' label='Rank by Value' initial='Select' onChange={e => sortSeries(e.target.value)} options={['asc', 'desc']} />}
1150
- {/* {visHasDataSuppression() && <DataSuppression config={config} updateConfig={updateConfig} data={data} />} */}
1151
- {visSupportsPreliminaryData() && <PreliminaryData config={config} updateConfig={updateConfig} data={data} />}
1152
- </AccordionItemPanel>
1153
- </AccordionItem>
1154
- )}
1155
- <Panels.BoxPlot name='Measures' />
1156
- {/* Left Value Axis */}
1157
- {visSupportsLeftValueAxis() && (
1158
- <AccordionItem>
1159
- <AccordionItemHeading>
1160
- <AccordionItemButton>
1161
- {config.visualizationType === 'Pie' ? 'Data Format' : config.orientation === 'vertical' ? 'Left Value Axis' : 'Value Axis'}
1162
- {config.visualizationType === 'Pie' && !config.yAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1163
- </AccordionItemButton>
1164
- </AccordionItemHeading>
1165
- <AccordionItemPanel>
1166
- {config.visualizationType === 'Pie' && (
1167
- <Select
1168
- value={config.yAxis.dataKey || ''}
1114
+ )}
1115
+ {visSupportsRankByValue() && config.series && config.series.length === 1 && <Select fieldName='visualizationType' label='Rank by Value' initial='Select' onChange={e => sortSeries(e.target.value)} options={['asc', 'desc']} />}
1116
+ {/* {visHasDataSuppression() && <DataSuppression config={config} updateConfig={updateConfig} data={data} />} */}
1117
+ {visSupportsPreliminaryData() && <PreliminaryData config={config} updateConfig={updateConfig} data={data} />}
1118
+ </AccordionItemPanel>
1119
+ </AccordionItem>
1120
+ )}
1121
+ <Panels.BoxPlot name='Measures' />
1122
+ {/* Left Value Axis */}
1123
+ {visSupportsLeftValueAxis() && (
1124
+ <AccordionItem>
1125
+ <AccordionItemHeading>
1126
+ <AccordionItemButton>
1127
+ {config.visualizationType === 'Pie' ? 'Data Format' : config.orientation === 'vertical' ? 'Left Value Axis' : 'Value Axis'}
1128
+ {config.visualizationType === 'Pie' && !config.yAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1129
+ </AccordionItemButton>
1130
+ </AccordionItemHeading>
1131
+ <AccordionItemPanel>
1132
+ {config.visualizationType === 'Pie' && (
1133
+ <Select
1134
+ value={config.yAxis.dataKey || ''}
1135
+ section='yAxis'
1136
+ fieldName='dataKey'
1137
+ label='Data Column'
1138
+ initial='Select'
1139
+ required={true}
1140
+ updateField={updateField}
1141
+ options={getColumns(false)}
1142
+ tooltip={
1143
+ <Tooltip style={{ textTransform: 'none' }}>
1144
+ <Tooltip.Target>
1145
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1146
+ </Tooltip.Target>
1147
+ <Tooltip.Content>
1148
+ <p>Select the source data to be visually represented.</p>
1149
+ </Tooltip.Content>
1150
+ </Tooltip>
1151
+ }
1152
+ />
1153
+ )}
1154
+ {config.visualizationType !== 'Pie' && (
1155
+ <>
1156
+ <TextField value={config.yAxis.label} section='yAxis' fieldName='label' label='Label ' updateField={updateField} />
1157
+ {config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && !['Box Plot', 'Deviation Bar', 'Forest Plot'].includes(config.visualizationType) && (
1158
+ <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />
1159
+ )}
1160
+ <TextField value={config.yAxis.numTicks} placeholder='Auto' type='number' section='yAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1161
+ <TextField
1162
+ value={config.yAxis.size}
1163
+ type='number'
1169
1164
  section='yAxis'
1170
- fieldName='dataKey'
1171
- label='Data Column'
1172
- initial='Select'
1173
- required={true}
1165
+ fieldName='size'
1166
+ label={config.orientation === 'horizontal' ? 'Size (Height)' : 'Size (Width)'}
1167
+ className='number-narrow'
1174
1168
  updateField={updateField}
1175
- options={getColumns(false)}
1176
1169
  tooltip={
1177
1170
  <Tooltip style={{ textTransform: 'none' }}>
1178
1171
  <Tooltip.Target>
1179
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1172
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1180
1173
  </Tooltip.Target>
1181
1174
  <Tooltip.Content>
1182
- <p>Select the source data to be visually represented.</p>
1175
+ <p>{`Increase the size if elements in the ${config.orientation} axis are being crowded or hidden behind other elements. Decrease if less space is required for the value axis.`}</p>
1183
1176
  </Tooltip.Content>
1184
1177
  </Tooltip>
1185
1178
  }
1186
1179
  />
1187
- )}
1188
- {config.visualizationType !== 'Pie' && (
1189
- <>
1190
- <TextField value={config.yAxis.label} section='yAxis' fieldName='label' label='Label ' updateField={updateField} />
1191
- {config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && !['Box Plot', 'Deviation Bar', 'Forest Plot'].includes(config.visualizationType) && (
1192
- <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />
1193
- )}
1194
- <TextField value={config.yAxis.numTicks} placeholder='Auto' type='number' section='yAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1180
+ {config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
1181
+ {(config.orientation === 'vertical' || !config.isResponsiveTicks) && <TextField value={config.yAxis.tickRotation || 0} type='number' min={0} section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1182
+ {config.isResponsiveTicks && config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && (
1195
1183
  <TextField
1196
- value={config.yAxis.size}
1184
+ value={config.xAxis.maxTickRotation}
1197
1185
  type='number'
1198
- section='yAxis'
1199
- fieldName='size'
1200
- label={config.orientation === 'horizontal' ? 'Size (Height)' : 'Size (Width)'}
1186
+ min={0}
1187
+ section='xAxis'
1188
+ fieldName='maxTickRotation'
1189
+ label='Max Tick Rotation'
1201
1190
  className='number-narrow'
1202
1191
  updateField={updateField}
1203
1192
  tooltip={
@@ -1206,552 +1195,523 @@ const EditorPanel = () => {
1206
1195
  <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1207
1196
  </Tooltip.Target>
1208
1197
  <Tooltip.Content>
1209
- <p>{`Increase the size if elements in the ${config.orientation} axis are being crowded or hidden behind other elements. Decrease if less space is required for the value axis.`}</p>
1198
+ <p>Degrees ticks will be rotated if values overlap, especially in smaller viewports.</p>
1210
1199
  </Tooltip.Content>
1211
1200
  </Tooltip>
1212
1201
  }
1213
1202
  />
1214
- {config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
1215
- {(config.orientation === 'vertical' || !config.isResponsiveTicks) && <TextField value={config.yAxis.tickRotation || 0} type='number' min={0} section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1216
- {config.isResponsiveTicks && config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && (
1217
- <TextField
1218
- value={config.xAxis.maxTickRotation}
1219
- type='number'
1220
- min={0}
1221
- section='xAxis'
1222
- fieldName='maxTickRotation'
1223
- label='Max Tick Rotation'
1224
- className='number-narrow'
1225
- updateField={updateField}
1226
- tooltip={
1227
- <Tooltip style={{ textTransform: 'none' }}>
1228
- <Tooltip.Target>
1229
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1230
- </Tooltip.Target>
1231
- <Tooltip.Content>
1232
- <p>Degrees ticks will be rotated if values overlap, especially in smaller viewports.</p>
1233
- </Tooltip.Content>
1234
- </Tooltip>
1235
- }
1236
- />
1237
- )}
1238
-
1239
- {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
1240
- {/* <TextField value={config.yAxis.axisPadding} type='number' max={10} min={0} section='yAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
1241
- {config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
1242
- {visSupportsValueAxisGridLines() && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Show Gridlines' updateField={updateField} />}
1243
- <CheckBox value={config.yAxis.enablePadding} section='yAxis' fieldName='enablePadding' label='Add Padding to Value Axis Scale' updateField={updateField} />
1244
- {config.yAxis.enablePadding && <TextField type='number' section='yAxis' fieldName='scalePadding' label='Padding Percentage' className='number-narrow' updateField={updateField} value={config.yAxis.scalePadding} />}
1245
- {config.visualizationSubType === 'regular' && config.visualizationType !== 'Forest Plot' && <CheckBox value={config.useLogScale} fieldName='useLogScale' label='use logarithmic scale' updateField={updateField} />}
1246
- </>
1247
- )}
1248
- <span className='divider-heading'>Number Formatting</span>
1249
- <CheckBox value={config.dataFormat.commas} section='dataFormat' fieldName='commas' label='Add commas' updateField={updateField} />
1250
- <CheckBox
1251
- value={config.dataFormat.abbreviated}
1203
+ )}
1204
+
1205
+ {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
1206
+ {/* <TextField value={config.yAxis.axisPadding} type='number' max={10} min={0} section='yAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
1207
+ {config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
1208
+ {visSupportsValueAxisGridLines() && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Show Gridlines' updateField={updateField} />}
1209
+ <CheckBox value={config.yAxis.enablePadding} section='yAxis' fieldName='enablePadding' label='Add Padding to Value Axis Scale' updateField={updateField} />
1210
+ {config.yAxis.enablePadding && <TextField type='number' section='yAxis' fieldName='scalePadding' label='Padding Percentage' className='number-narrow' updateField={updateField} value={config.yAxis.scalePadding} />}
1211
+ {config.visualizationSubType === 'regular' && config.visualizationType !== 'Forest Plot' && <CheckBox value={config.useLogScale} fieldName='useLogScale' label='use logarithmic scale' updateField={updateField} />}
1212
+ </>
1213
+ )}
1214
+ <span className='divider-heading'>Number Formatting</span>
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
+ />
1232
+ <CheckBox
1233
+ value={config.dataFormat.abbreviated}
1234
+ section='dataFormat'
1235
+ fieldName='abbreviated'
1236
+ label='Abbreviate Axis Values'
1237
+ updateField={updateField}
1238
+ tooltip={
1239
+ <Tooltip style={{ textTransform: 'none' }}>
1240
+ <Tooltip.Target>
1241
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1242
+ </Tooltip.Target>
1243
+ <Tooltip.Content>
1244
+ <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
1245
+ </Tooltip.Content>
1246
+ </Tooltip>
1247
+ }
1248
+ />
1249
+ <TextField value={config.dataFormat.roundTo ? config.dataFormat.roundTo : 0} type='number' section='dataFormat' fieldName='roundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1250
+ <div className='two-col-inputs'>
1251
+ <TextField
1252
+ value={config.dataFormat.prefix}
1252
1253
  section='dataFormat'
1253
- fieldName='abbreviated'
1254
- label='Abbreviate Axis Values'
1254
+ fieldName='prefix'
1255
+ label='Prefix'
1255
1256
  updateField={updateField}
1256
1257
  tooltip={
1257
1258
  <Tooltip style={{ textTransform: 'none' }}>
1258
1259
  <Tooltip.Target>
1259
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1260
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1260
1261
  </Tooltip.Target>
1261
1262
  <Tooltip.Content>
1262
- <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
1263
+ {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1264
+ {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
1263
1265
  </Tooltip.Content>
1264
1266
  </Tooltip>
1265
1267
  }
1266
1268
  />
1267
- <TextField value={config.dataFormat.roundTo ? config.dataFormat.roundTo : 0} type='number' section='dataFormat' fieldName='roundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1268
- <div className='two-col-inputs'>
1269
- <TextField
1270
- value={config.dataFormat.prefix}
1271
- section='dataFormat'
1272
- fieldName='prefix'
1273
- label='Prefix'
1274
- updateField={updateField}
1275
- tooltip={
1276
- <Tooltip style={{ textTransform: 'none' }}>
1277
- <Tooltip.Target>
1278
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1279
- </Tooltip.Target>
1280
- <Tooltip.Content>
1281
- {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1282
- {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
1283
- </Tooltip.Content>
1284
- </Tooltip>
1285
- }
1286
- />
1287
- <TextField
1288
- value={config.dataFormat.suffix}
1289
- section='dataFormat'
1290
- fieldName='suffix'
1291
- label='Suffix'
1292
- updateField={updateField}
1293
- tooltip={
1294
- <Tooltip style={{ textTransform: 'none' }}>
1295
- <Tooltip.Target>
1296
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1297
- </Tooltip.Target>
1298
- <Tooltip.Content>
1299
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1300
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1301
- </Tooltip.Content>
1302
- </Tooltip>
1303
- }
1304
- />
1305
- </div>
1269
+ <TextField
1270
+ value={config.dataFormat.suffix}
1271
+ section='dataFormat'
1272
+ fieldName='suffix'
1273
+ label='Suffix'
1274
+ updateField={updateField}
1275
+ tooltip={
1276
+ <Tooltip style={{ textTransform: 'none' }}>
1277
+ <Tooltip.Target>
1278
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1279
+ </Tooltip.Target>
1280
+ <Tooltip.Content>
1281
+ {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1282
+ {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1283
+ </Tooltip.Content>
1284
+ </Tooltip>
1285
+ }
1286
+ />
1287
+ </div>
1306
1288
 
1307
- {config.orientation === 'horizontal' ? ( // horizontal - x is vertical y is horizontal
1289
+ {config.orientation === 'horizontal' ? ( // horizontal - x is vertical y is horizontal
1290
+ <>
1291
+ {visSupportsValueAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
1292
+ {visSupportsValueAxisLabels() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
1293
+ {visSupportsValueAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
1294
+ {visSupportsValueAxisMax() && <TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='max value' type='number' placeholder='Auto' updateField={updateField} />}
1295
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1296
+ {visSupportsValueAxisMin() && <TextField value={config.xAxis.min} section='xAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />}
1297
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1298
+ {config.visualizationType === 'Deviation Bar' && (
1299
+ <>
1300
+ <TextField value={config.xAxis.target} section='xAxis' fieldName='target' type='number' label='Deviation point' placeholder='Auto' updateField={updateField} />
1301
+ <TextField value={config.xAxis.targetLabel || 'Target'} section='xAxis' fieldName='targetLabel' type='text' label='Deviation point Label' updateField={updateField} />
1302
+ <CheckBox value={config.xAxis.showTargetLabel} section='xAxis' fieldName='showTargetLabel' label='Show Deviation point label' updateField={updateField} />
1303
+ </>
1304
+ )}
1305
+ </>
1306
+ ) : (
1307
+ config.visualizationType !== 'Pie' && (
1308
1308
  <>
1309
- {visSupportsValueAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
1310
- {visSupportsValueAxisLabels() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
1311
- {visSupportsValueAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
1312
- {visSupportsValueAxisMax() && <TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='max value' type='number' placeholder='Auto' updateField={updateField} />}
1309
+ <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1310
+ <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1311
+ <CheckBox value={config.yAxis.hideTicks} section='yAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1312
+
1313
+ <TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='left axis max value' placeholder='Auto' updateField={updateField} />
1313
1314
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1314
- {visSupportsValueAxisMin() && <TextField value={config.xAxis.min} section='xAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />}
1315
+ <TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='left axis min value' placeholder='Auto' updateField={updateField} />
1315
1316
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1316
- {config.visualizationType === 'Deviation Bar' && (
1317
- <>
1318
- <TextField value={config.xAxis.target} section='xAxis' fieldName='target' type='number' label='Deviation point' placeholder='Auto' updateField={updateField} />
1319
- <TextField value={config.xAxis.targetLabel || 'Target'} section='xAxis' fieldName='targetLabel' type='text' label='Deviation point Label' updateField={updateField} />
1320
- <CheckBox value={config.xAxis.showTargetLabel} section='xAxis' fieldName='showTargetLabel' label='Show Deviation point label' updateField={updateField} />
1321
- </>
1322
- )}
1323
1317
  </>
1324
- ) : (
1325
- config.visualizationType !== 'Pie' && (
1326
- <>
1327
- <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1328
- <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1329
- <CheckBox value={config.yAxis.hideTicks} section='yAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1330
-
1331
- <TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='left axis max value' placeholder='Auto' updateField={updateField} />
1332
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1333
- <TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='left axis min value' placeholder='Auto' updateField={updateField} />
1334
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1335
- </>
1336
- )
1337
- )}
1338
-
1339
- {/* start: anchors */}
1340
- {visHasAnchors() && config.orientation !== 'horizontal' && (
1341
- <div className='edit-block'>
1342
- <span className='edit-label column-heading'>Anchors</span>
1343
- <Accordion allowZeroExpanded>
1344
- {config.yAxis?.anchors?.map((anchor, index) => (
1345
- <AccordionItem className='series-item series-item--chart' key={`yaxis-anchors-2-${index}`}>
1346
- <AccordionItemHeading className='series-item__title'>
1347
- <>
1348
- <AccordionItemButton className={'accordion__button accordion__button'}>
1349
- Anchor {index + 1}
1350
- <button
1351
- className='series-list__remove'
1352
- onClick={e => {
1353
- e.preventDefault()
1354
- const copiedAnchorGroups = [...config.yAxis.anchors]
1355
- copiedAnchorGroups.splice(index, 1)
1356
- updateConfig({
1357
- ...config,
1358
- yAxis: {
1359
- ...config.yAxis,
1360
- anchors: copiedAnchorGroups
1361
- }
1362
- })
1363
- }}
1364
- >
1365
- Remove
1366
- </button>
1367
- </AccordionItemButton>
1368
- </>
1369
- </AccordionItemHeading>
1370
- <AccordionItemPanel>
1371
- <label>
1372
- <span>Anchor Value</span>
1373
- <Tooltip style={{ textTransform: 'none' }}>
1374
- <Tooltip.Target>
1375
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1376
- </Tooltip.Target>
1377
- <Tooltip.Content>
1378
- <p>Enter the value as its shown in the data column</p>
1379
- </Tooltip.Content>
1380
- </Tooltip>
1381
- <input
1382
- type='text'
1383
- value={config.yAxis.anchors[index].value ? config.yAxis.anchors[index].value : ''}
1384
- onChange={e => {
1385
- e.preventDefault()
1386
- const copiedAnchors = [...config.yAxis.anchors]
1387
- copiedAnchors[index].value = e.target.value
1388
- updateConfig({
1389
- ...config,
1390
- yAxis: {
1391
- ...config.yAxis,
1392
- anchors: copiedAnchors
1393
- }
1394
- })
1395
- }}
1396
- />
1397
- </label>
1398
-
1399
- <label>
1400
- <span>Anchor Color</span>
1401
- <input
1402
- type='text'
1403
- value={config.yAxis.anchors[index].color ? config.yAxis.anchors[index].color : ''}
1404
- onChange={e => {
1318
+ )
1319
+ )}
1320
+
1321
+ {/* start: anchors */}
1322
+ {visHasAnchors() && config.orientation !== 'horizontal' && (
1323
+ <div className='edit-block'>
1324
+ <span className='edit-label column-heading'>Anchors</span>
1325
+ <Accordion allowZeroExpanded>
1326
+ {config.yAxis?.anchors?.map((anchor, index) => (
1327
+ <AccordionItem className='series-item series-item--chart' key={`yaxis-anchors-2-${index}`}>
1328
+ <AccordionItemHeading className='series-item__title'>
1329
+ <>
1330
+ <AccordionItemButton className={'accordion__button accordion__button'}>
1331
+ Anchor {index + 1}
1332
+ <button
1333
+ className='series-list__remove'
1334
+ onClick={e => {
1405
1335
  e.preventDefault()
1406
- const copiedAnchors = [...config.yAxis.anchors]
1407
- copiedAnchors[index].color = e.target.value
1336
+ const copiedAnchorGroups = [...config.yAxis.anchors]
1337
+ copiedAnchorGroups.splice(index, 1)
1408
1338
  updateConfig({
1409
1339
  ...config,
1410
1340
  yAxis: {
1411
1341
  ...config.yAxis,
1412
- anchors: copiedAnchors
1413
- }
1414
- })
1415
- }}
1416
- />
1417
- </label>
1418
-
1419
- <label>
1420
- Anchor Line Style
1421
- <select
1422
- value={config.yAxis.anchors[index].lineStyle || ''}
1423
- onChange={e => {
1424
- const copiedAnchors = [...config.yAxis.anchors]
1425
- copiedAnchors[index].lineStyle = e.target.value
1426
- updateConfig({
1427
- ...config,
1428
- yAxis: {
1429
- ...config.yAxis,
1430
- anchors: copiedAnchors
1342
+ anchors: copiedAnchorGroups
1431
1343
  }
1432
1344
  })
1433
1345
  }}
1434
1346
  >
1435
- <option>Select</option>
1436
- {lineOptions.map(line => (
1437
- <option key={line.key}>{line.value}</option>
1438
- ))}
1439
- </select>
1440
- </label>
1441
- </AccordionItemPanel>
1442
- </AccordionItem>
1443
- ))}
1444
- </Accordion>
1445
-
1446
- <button
1447
- className='btn full-width'
1448
- onClick={e => {
1449
- e.preventDefault()
1450
- const anchors = [...config.yAxis.anchors]
1451
- anchors.push({} as Anchor)
1452
- updateConfig({
1453
- ...config,
1454
- yAxis: {
1455
- ...config.yAxis,
1456
- anchors
1457
- }
1458
- })
1459
- }}
1460
- >
1461
- Add Anchor
1462
- </button>
1463
- </div>
1464
- )}
1347
+ Remove
1348
+ </button>
1349
+ </AccordionItemButton>
1350
+ </>
1351
+ </AccordionItemHeading>
1352
+ <AccordionItemPanel>
1353
+ <label>
1354
+ <span>Anchor Value</span>
1355
+ <Tooltip style={{ textTransform: 'none' }}>
1356
+ <Tooltip.Target>
1357
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1358
+ </Tooltip.Target>
1359
+ <Tooltip.Content>
1360
+ <p>Enter the value as its shown in the data column</p>
1361
+ </Tooltip.Content>
1362
+ </Tooltip>
1363
+ <input
1364
+ type='text'
1365
+ value={config.yAxis.anchors[index].value ? config.yAxis.anchors[index].value : ''}
1366
+ onChange={e => {
1367
+ e.preventDefault()
1368
+ const copiedAnchors = [...config.yAxis.anchors]
1369
+ copiedAnchors[index].value = e.target.value
1370
+ updateConfig({
1371
+ ...config,
1372
+ yAxis: {
1373
+ ...config.yAxis,
1374
+ anchors: copiedAnchors
1375
+ }
1376
+ })
1377
+ }}
1378
+ />
1379
+ </label>
1465
1380
 
1466
- {visHasAnchors() && config.orientation === 'horizontal' && (
1467
- <div className='edit-block'>
1468
- <span className='edit-label column-heading'>Anchors</span>
1469
- <Accordion allowZeroExpanded>
1470
- {config.xAxis?.anchors?.map((anchor, index) => (
1471
- <AccordionItem className='series-item series-item--chart' key={`xaxis-anchors-${index}`}>
1472
- <AccordionItemHeading className='series-item__title'>
1473
- <>
1474
- <AccordionItemButton className={'accordion__button accordion__button'}>
1475
- Anchor {index + 1}
1476
- <button
1477
- className='series-list__remove'
1478
- onClick={e => {
1479
- e.preventDefault()
1480
- const copiedAnchorGroups = [...config.xAxis.anchors]
1481
- copiedAnchorGroups.splice(index, 1)
1482
- updateConfig({
1483
- ...config,
1484
- xAxis: {
1485
- ...config.xAxis,
1486
- anchors: copiedAnchorGroups
1487
- }
1488
- })
1489
- }}
1490
- >
1491
- Remove
1492
- </button>
1493
- </AccordionItemButton>
1494
- </>
1495
- </AccordionItemHeading>
1496
- <AccordionItemPanel>
1497
- <label>
1498
- <span>Anchor Value</span>
1499
- <Tooltip style={{ textTransform: 'none' }}>
1500
- <Tooltip.Target>
1501
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1502
- </Tooltip.Target>
1503
- <Tooltip.Content>
1504
- <p>Enter the value as its shown in the data column</p>
1505
- </Tooltip.Content>
1506
- </Tooltip>
1507
- <input
1508
- type='text'
1509
- value={config.xAxis.anchors[index].value ? config.xAxis.anchors[index].value : ''}
1510
- onChange={e => {
1511
- e.preventDefault()
1512
- const copiedAnchors = [...config.xAxis.anchors]
1513
- copiedAnchors[index].value = e.target.value
1514
- updateConfig({
1515
- ...config,
1516
- xAxis: {
1517
- ...config.xAxis,
1518
- anchors: copiedAnchors
1519
- }
1520
- })
1521
- }}
1522
- />
1523
- </label>
1524
-
1525
- <label>
1526
- <span>Anchor Color</span>
1527
- <input
1528
- type='text'
1529
- value={config.xAxis.anchors[index].color ? config.xAxis.anchors[index].color : ''}
1530
- onChange={e => {
1381
+ <label>
1382
+ <span>Anchor Color</span>
1383
+ <input
1384
+ type='text'
1385
+ value={config.yAxis.anchors[index].color ? config.yAxis.anchors[index].color : ''}
1386
+ onChange={e => {
1387
+ e.preventDefault()
1388
+ const copiedAnchors = [...config.yAxis.anchors]
1389
+ copiedAnchors[index].color = e.target.value
1390
+ updateConfig({
1391
+ ...config,
1392
+ yAxis: {
1393
+ ...config.yAxis,
1394
+ anchors: copiedAnchors
1395
+ }
1396
+ })
1397
+ }}
1398
+ />
1399
+ </label>
1400
+
1401
+ <label>
1402
+ Anchor Line Style
1403
+ <select
1404
+ value={config.yAxis.anchors[index].lineStyle || ''}
1405
+ onChange={e => {
1406
+ const copiedAnchors = [...config.yAxis.anchors]
1407
+ copiedAnchors[index].lineStyle = e.target.value
1408
+ updateConfig({
1409
+ ...config,
1410
+ yAxis: {
1411
+ ...config.yAxis,
1412
+ anchors: copiedAnchors
1413
+ }
1414
+ })
1415
+ }}
1416
+ >
1417
+ <option>Select</option>
1418
+ {lineOptions.map(line => (
1419
+ <option key={line.key}>{line.value}</option>
1420
+ ))}
1421
+ </select>
1422
+ </label>
1423
+ </AccordionItemPanel>
1424
+ </AccordionItem>
1425
+ ))}
1426
+ </Accordion>
1427
+
1428
+ <button
1429
+ className='btn full-width'
1430
+ onClick={e => {
1431
+ e.preventDefault()
1432
+ const anchors = [...config.yAxis.anchors]
1433
+ anchors.push({} as Anchor)
1434
+ updateConfig({
1435
+ ...config,
1436
+ yAxis: {
1437
+ ...config.yAxis,
1438
+ anchors
1439
+ }
1440
+ })
1441
+ }}
1442
+ >
1443
+ Add Anchor
1444
+ </button>
1445
+ </div>
1446
+ )}
1447
+
1448
+ {visHasAnchors() && config.orientation === 'horizontal' && (
1449
+ <div className='edit-block'>
1450
+ <span className='edit-label column-heading'>Anchors</span>
1451
+ <Accordion allowZeroExpanded>
1452
+ {config.xAxis?.anchors?.map((anchor, index) => (
1453
+ <AccordionItem className='series-item series-item--chart' key={`xaxis-anchors-${index}`}>
1454
+ <AccordionItemHeading className='series-item__title'>
1455
+ <>
1456
+ <AccordionItemButton className={'accordion__button accordion__button'}>
1457
+ Anchor {index + 1}
1458
+ <button
1459
+ className='series-list__remove'
1460
+ onClick={e => {
1531
1461
  e.preventDefault()
1532
- const copiedAnchors = [...config.xAxis.anchors]
1533
- copiedAnchors[index].color = e.target.value
1462
+ const copiedAnchorGroups = [...config.xAxis.anchors]
1463
+ copiedAnchorGroups.splice(index, 1)
1534
1464
  updateConfig({
1535
1465
  ...config,
1536
1466
  xAxis: {
1537
1467
  ...config.xAxis,
1538
- anchors: copiedAnchors
1539
- }
1540
- })
1541
- }}
1542
- />
1543
- </label>
1544
-
1545
- <label>
1546
- Anchor Line Style
1547
- <select
1548
- value={config.xAxis.anchors[index].lineStyle || ''}
1549
- onChange={e => {
1550
- const copiedAnchors = [...config.xAxis.anchors]
1551
- copiedAnchors[index].lineStyle = e.target.value
1552
- updateConfig({
1553
- ...config,
1554
- xAxis: {
1555
- ...config.xAxis,
1556
- anchors: copiedAnchors
1468
+ anchors: copiedAnchorGroups
1557
1469
  }
1558
1470
  })
1559
1471
  }}
1560
1472
  >
1561
- <option>Select</option>
1562
- {lineOptions.map(line => (
1563
- <option key={line.key}>{line.value}</option>
1564
- ))}
1565
- </select>
1566
- </label>
1567
- </AccordionItemPanel>
1568
- </AccordionItem>
1569
- ))}
1570
- </Accordion>
1571
-
1572
- <button
1573
- className='btn full-width'
1574
- onClick={e => {
1575
- e.preventDefault()
1576
- const anchors = [...config.xAxis.anchors]
1577
- anchors.push({} as Anchor)
1578
- updateConfig({
1579
- ...config,
1580
- xAxis: {
1581
- ...config.xAxis,
1582
- anchors
1583
- }
1584
- })
1585
- }}
1586
- >
1587
- Add Anchor
1588
- </button>
1589
- </div>
1590
- )}
1591
- {/* end: anchors */}
1592
- </AccordionItemPanel>
1593
- </AccordionItem>
1594
- )}
1595
- {/* Right Value Axis Settings */}
1596
- {hasRightAxis && (
1597
- <AccordionItem>
1598
- <AccordionItemHeading>
1599
- <AccordionItemButton>Right Value Axis</AccordionItemButton>
1600
- </AccordionItemHeading>
1601
- <AccordionItemPanel>
1602
- <TextField value={config.yAxis.rightLabel} section='yAxis' fieldName='rightLabel' label='Label' updateField={updateField} />
1603
- <TextField value={config.yAxis.rightNumTicks} placeholder='Auto' type='number' section='yAxis' fieldName='rightNumTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1604
- <TextField value={config.yAxis.rightAxisSize} type='number' section='yAxis' fieldName='rightAxisSize' label='Size (Width)' className='number-narrow' updateField={updateField} />
1605
- <TextField value={config.yAxis.rightLabelOffsetSize} type='number' section='yAxis' fieldName='rightLabelOffsetSize' label='Label Offset' className='number-narrow' updateField={updateField} />
1606
-
1607
- <span className='divider-heading'>Number Formatting</span>
1608
- <CheckBox value={config.dataFormat.rightCommas} section='dataFormat' fieldName='rightCommas' label='Add commas' updateField={updateField} />
1609
- <TextField value={config.dataFormat.rightRoundTo} type='number' section='dataFormat' fieldName='rightRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1610
- <div className='two-col-inputs'>
1611
- <TextField
1612
- value={config.dataFormat.rightPrefix}
1613
- section='dataFormat'
1614
- fieldName='rightPrefix'
1615
- label='Prefix'
1616
- updateField={updateField}
1617
- tooltip={
1618
- <Tooltip style={{ textTransform: 'none' }}>
1619
- <Tooltip.Target>
1620
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1621
- </Tooltip.Target>
1622
- <Tooltip.Content>
1623
- {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1624
- {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
1625
- </Tooltip.Content>
1626
- </Tooltip>
1627
- }
1628
- />
1629
- <TextField
1630
- value={config.dataFormat.rightSuffix}
1631
- section='dataFormat'
1632
- fieldName='rightSuffix'
1633
- label='Suffix'
1634
- updateField={updateField}
1635
- tooltip={
1636
- <Tooltip style={{ textTransform: 'none' }}>
1637
- <Tooltip.Target>
1638
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1639
- </Tooltip.Target>
1640
- <Tooltip.Content>
1641
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1642
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1643
- </Tooltip.Content>
1644
- </Tooltip>
1645
- }
1646
- />
1473
+ Remove
1474
+ </button>
1475
+ </AccordionItemButton>
1476
+ </>
1477
+ </AccordionItemHeading>
1478
+ <AccordionItemPanel>
1479
+ <label>
1480
+ <span>Anchor Value</span>
1481
+ <Tooltip style={{ textTransform: 'none' }}>
1482
+ <Tooltip.Target>
1483
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1484
+ </Tooltip.Target>
1485
+ <Tooltip.Content>
1486
+ <p>Enter the value as its shown in the data column</p>
1487
+ </Tooltip.Content>
1488
+ </Tooltip>
1489
+ <input
1490
+ type='text'
1491
+ value={config.xAxis.anchors[index].value ? config.xAxis.anchors[index].value : ''}
1492
+ onChange={e => {
1493
+ e.preventDefault()
1494
+ const copiedAnchors = [...config.xAxis.anchors]
1495
+ copiedAnchors[index].value = e.target.value
1496
+ updateConfig({
1497
+ ...config,
1498
+ xAxis: {
1499
+ ...config.xAxis,
1500
+ anchors: copiedAnchors
1501
+ }
1502
+ })
1503
+ }}
1504
+ />
1505
+ </label>
1506
+
1507
+ <label>
1508
+ <span>Anchor Color</span>
1509
+ <input
1510
+ type='text'
1511
+ value={config.xAxis.anchors[index].color ? config.xAxis.anchors[index].color : ''}
1512
+ onChange={e => {
1513
+ e.preventDefault()
1514
+ const copiedAnchors = [...config.xAxis.anchors]
1515
+ copiedAnchors[index].color = e.target.value
1516
+ updateConfig({
1517
+ ...config,
1518
+ xAxis: {
1519
+ ...config.xAxis,
1520
+ anchors: copiedAnchors
1521
+ }
1522
+ })
1523
+ }}
1524
+ />
1525
+ </label>
1526
+
1527
+ <label>
1528
+ Anchor Line Style
1529
+ <select
1530
+ value={config.xAxis.anchors[index].lineStyle || ''}
1531
+ onChange={e => {
1532
+ const copiedAnchors = [...config.xAxis.anchors]
1533
+ copiedAnchors[index].lineStyle = e.target.value
1534
+ updateConfig({
1535
+ ...config,
1536
+ xAxis: {
1537
+ ...config.xAxis,
1538
+ anchors: copiedAnchors
1539
+ }
1540
+ })
1541
+ }}
1542
+ >
1543
+ <option>Select</option>
1544
+ {lineOptions.map(line => (
1545
+ <option key={line.key}>{line.value}</option>
1546
+ ))}
1547
+ </select>
1548
+ </label>
1549
+ </AccordionItemPanel>
1550
+ </AccordionItem>
1551
+ ))}
1552
+ </Accordion>
1553
+
1554
+ <button
1555
+ className='btn full-width'
1556
+ onClick={e => {
1557
+ e.preventDefault()
1558
+ const anchors = [...config.xAxis.anchors]
1559
+ anchors.push({} as Anchor)
1560
+ updateConfig({
1561
+ ...config,
1562
+ xAxis: {
1563
+ ...config.xAxis,
1564
+ anchors
1565
+ }
1566
+ })
1567
+ }}
1568
+ >
1569
+ Add Anchor
1570
+ </button>
1647
1571
  </div>
1572
+ )}
1573
+ {/* end: anchors */}
1574
+ </AccordionItemPanel>
1575
+ </AccordionItem>
1576
+ )}
1577
+ {/* Right Value Axis Settings */}
1578
+ {hasRightAxis && (
1579
+ <AccordionItem>
1580
+ <AccordionItemHeading>
1581
+ <AccordionItemButton>Right Value Axis</AccordionItemButton>
1582
+ </AccordionItemHeading>
1583
+ <AccordionItemPanel>
1584
+ <TextField value={config.yAxis.rightLabel} section='yAxis' fieldName='rightLabel' label='Label' updateField={updateField} />
1585
+ <TextField value={config.yAxis.rightNumTicks} placeholder='Auto' type='number' section='yAxis' fieldName='rightNumTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1586
+ <TextField value={config.yAxis.rightAxisSize} type='number' section='yAxis' fieldName='rightAxisSize' label='Size (Width)' className='number-narrow' updateField={updateField} />
1587
+ <TextField value={config.yAxis.rightLabelOffsetSize} type='number' section='yAxis' fieldName='rightLabelOffsetSize' label='Label Offset' className='number-narrow' updateField={updateField} />
1588
+
1589
+ <span className='divider-heading'>Number Formatting</span>
1590
+ <CheckBox value={config.dataFormat.rightCommas} section='dataFormat' fieldName='rightCommas' label='Add commas' updateField={updateField} />
1591
+ <TextField value={config.dataFormat.rightRoundTo} type='number' section='dataFormat' fieldName='rightRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1592
+ <div className='two-col-inputs'>
1593
+ <TextField
1594
+ value={config.dataFormat.rightPrefix}
1595
+ section='dataFormat'
1596
+ fieldName='rightPrefix'
1597
+ label='Prefix'
1598
+ updateField={updateField}
1599
+ tooltip={
1600
+ <Tooltip style={{ textTransform: 'none' }}>
1601
+ <Tooltip.Target>
1602
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1603
+ </Tooltip.Target>
1604
+ <Tooltip.Content>
1605
+ {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1606
+ {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
1607
+ </Tooltip.Content>
1608
+ </Tooltip>
1609
+ }
1610
+ />
1611
+ <TextField
1612
+ value={config.dataFormat.rightSuffix}
1613
+ section='dataFormat'
1614
+ fieldName='rightSuffix'
1615
+ label='Suffix'
1616
+ updateField={updateField}
1617
+ tooltip={
1618
+ <Tooltip style={{ textTransform: 'none' }}>
1619
+ <Tooltip.Target>
1620
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1621
+ </Tooltip.Target>
1622
+ <Tooltip.Content>
1623
+ {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1624
+ {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1625
+ </Tooltip.Content>
1626
+ </Tooltip>
1627
+ }
1628
+ />
1629
+ </div>
1630
+
1631
+ <CheckBox value={config.yAxis.rightHideAxis} section='yAxis' fieldName='rightHideAxis' label='Hide Axis' updateField={updateField} />
1632
+ <CheckBox value={config.yAxis.rightHideLabel} section='yAxis' fieldName='rightHideLabel' label='Hide Label' updateField={updateField} />
1633
+ <CheckBox value={config.yAxis.rightHideTicks} section='yAxis' fieldName='rightHideTicks' label='Hide Ticks' updateField={updateField} />
1634
+
1635
+ <TextField value={config.yAxis.max} section='yAxis' fieldName='rightMax' type='number' label='right axis max value' placeholder='Auto' updateField={updateField} />
1636
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.rightMaxMessage}</span>
1637
+ <TextField value={config.yAxis.min} section='yAxis' fieldName='rightMin' type='number' label='right axis min value' placeholder='Auto' updateField={updateField} />
1638
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1639
+ </AccordionItemPanel>
1640
+ </AccordionItem>
1641
+ )}
1642
+ {visSupportsDateCategoryAxis() && (
1643
+ <AccordionItem>
1644
+ <AccordionItemHeading>
1645
+ <AccordionItemButton>
1646
+ {config.visualizationType === 'Pie' ? 'Segments' : 'Date/Category Axis'}
1647
+ {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1648
+ </AccordionItemButton>
1649
+ </AccordionItemHeading>
1650
+ <AccordionItemPanel>
1651
+ {config.visualizationType !== 'Pie' && (
1652
+ <>
1653
+ {config.visualizationType !== 'Forest Plot' && (
1654
+ <>
1655
+ <label>
1656
+ <span className='edit-label'>
1657
+ Data Scaling Type
1658
+ <Tooltip style={{ textTransform: 'none', display: 'inline-block' }}>
1659
+ <Tooltip.Target>
1660
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1661
+ </Tooltip.Target>
1662
+ <Tooltip.Content>Linear scales are employed for quantitative data, while time scales are used for time-series data.</Tooltip.Content>
1663
+ </Tooltip>
1664
+ </span>
1665
+ <select
1666
+ value={config.xAxis.type}
1667
+ onChange={e =>
1668
+ updateConfig({
1669
+ ...config,
1670
+ xAxis: {
1671
+ ...config.xAxis,
1672
+ type: e.target.value
1673
+ }
1674
+ })
1675
+ }
1676
+ >
1677
+ <option value='categorical'>Categorical (Linear Scale)</option>
1678
+ <option value='date'>Date (Linear Scale)</option>
1679
+ <option value='date-time'>Date (Date Time Scale)</option>
1680
+ {config.visualizationType === 'Scatter Plot' && <option value={'continuous'}>Continuous</option>}
1681
+ </select>
1682
+ </label>
1648
1683
 
1649
- <CheckBox value={config.yAxis.rightHideAxis} section='yAxis' fieldName='rightHideAxis' label='Hide Axis' updateField={updateField} />
1650
- <CheckBox value={config.yAxis.rightHideLabel} section='yAxis' fieldName='rightHideLabel' label='Hide Label' updateField={updateField} />
1651
- <CheckBox value={config.yAxis.rightHideTicks} section='yAxis' fieldName='rightHideTicks' label='Hide Ticks' updateField={updateField} />
1684
+ <CheckBox value={config.xAxis.manual} section='xAxis' fieldName='manual' label='Manual Ticks' updateField={updateField} />
1652
1685
 
1653
- <TextField value={config.yAxis.max} section='yAxis' fieldName='rightMax' type='number' label='right axis max value' placeholder='Auto' updateField={updateField} />
1654
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.rightMaxMessage}</span>
1655
- <TextField value={config.yAxis.min} section='yAxis' fieldName='rightMin' type='number' label='right axis min value' placeholder='Auto' updateField={updateField} />
1656
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1657
- </AccordionItemPanel>
1658
- </AccordionItem>
1659
- )}
1660
- {visSupportsDateCategoryAxis() && (
1661
- <AccordionItem>
1662
- <AccordionItemHeading>
1663
- <AccordionItemButton>
1664
- {config.visualizationType === 'Pie' ? 'Segments' : 'Date/Category Axis'}
1665
- {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1666
- </AccordionItemButton>
1667
- </AccordionItemHeading>
1668
- <AccordionItemPanel>
1669
- {config.visualizationType !== 'Pie' && (
1670
- <>
1671
- {config.visualizationType !== 'Forest Plot' && (
1672
- <>
1673
- <label>
1674
- <span className='edit-label'>
1675
- Data Scaling Type
1676
- <Tooltip style={{ textTransform: 'none', display: 'inline-block' }}>
1686
+ {visSupportsDateCategoryAxisPadding() && (
1687
+ <TextField
1688
+ value={config.xAxis.padding}
1689
+ type='number'
1690
+ min={0}
1691
+ section='xAxis'
1692
+ fieldName='padding'
1693
+ label={'Padding (Percent)'}
1694
+ className='number-narrow'
1695
+ updateField={updateField}
1696
+ tooltip={
1697
+ <Tooltip style={{ textTransform: 'none' }}>
1677
1698
  <Tooltip.Target>
1678
1699
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1679
1700
  </Tooltip.Target>
1680
- <Tooltip.Content>Linear scales are employed for quantitative data, while time scales are used for time-series data.</Tooltip.Content>
1701
+ <Tooltip.Content>
1702
+ <p>For use with date scale. Extends the earliest and latest dates represented on the scale by the percentage specified.</p>
1703
+ </Tooltip.Content>
1681
1704
  </Tooltip>
1682
- </span>
1683
- <select
1684
- value={config.xAxis.type}
1685
- onChange={e =>
1686
- updateConfig({
1687
- ...config,
1688
- xAxis: {
1689
- ...config.xAxis,
1690
- type: e.target.value
1691
- }
1692
- })
1693
- }
1694
- >
1695
- <option value='categorical'>Categorical (Linear Scale)</option>
1696
- <option value='date'>Date (Linear Scale)</option>
1697
- <option value='date-time'>Date (Date Time Scale)</option>
1698
- {config.visualizationType === 'Scatter Plot' && <option value={'continuous'}>Continuous</option>}
1699
- </select>
1700
- </label>
1701
-
1702
- {visSupportsDateCategoryAxisPadding() && (
1703
- <TextField
1704
- value={config.xAxis.padding}
1705
- type='number'
1706
- min={0}
1707
- section='xAxis'
1708
- fieldName='padding'
1709
- label={'Padding (Percent)'}
1710
- className='number-narrow'
1711
- updateField={updateField}
1712
- tooltip={
1713
- <Tooltip style={{ textTransform: 'none' }}>
1714
- <Tooltip.Target>
1715
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1716
- </Tooltip.Target>
1717
- <Tooltip.Content>
1718
- <p>For use with date scale. Extends the earliest and latest dates represented on the scale by the percentage specified.</p>
1719
- </Tooltip.Content>
1720
- </Tooltip>
1721
- }
1722
- />
1723
- )}
1724
- </>
1725
- )}
1726
- <Select
1727
- value={config.xAxis.dataKey || setCategoryAxis() || ''}
1728
- section='xAxis'
1729
- fieldName='dataKey'
1730
- label='Data Key'
1731
- initial='Select'
1732
- required={true}
1733
- updateField={updateField}
1734
- options={getColumns(false)}
1735
- tooltip={
1736
- <Tooltip style={{ textTransform: 'none' }}>
1737
- <Tooltip.Target>
1738
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1739
- </Tooltip.Target>
1740
- <Tooltip.Content>
1741
- <p>Select the column or row containing the categories or dates for this axis. </p>
1742
- </Tooltip.Content>
1743
- </Tooltip>
1744
- }
1745
- />
1746
- </>
1747
- )}
1748
-
1749
- {config.visualizationType === 'Pie' && (
1705
+ }
1706
+ />
1707
+ )}
1708
+ </>
1709
+ )}
1750
1710
  <Select
1751
- value={config.xAxis.dataKey || ''}
1711
+ value={config.xAxis.dataKey || setCategoryAxis() || ''}
1752
1712
  section='xAxis'
1753
1713
  fieldName='dataKey'
1754
- label='Segment Labels'
1714
+ label='Data Key'
1755
1715
  initial='Select'
1756
1716
  required={true}
1757
1717
  updateField={updateField}
@@ -1762,1164 +1722,860 @@ const EditorPanel = () => {
1762
1722
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1763
1723
  </Tooltip.Target>
1764
1724
  <Tooltip.Content>
1765
- <p>Select the source row or column that contains the segment labels. Depending on the data structure, it may be listed as "Key."</p>
1725
+ <p>Select the column or row containing the categories or dates for this axis. </p>
1766
1726
  </Tooltip.Content>
1767
1727
  </Tooltip>
1768
1728
  }
1769
1729
  />
1770
- )}
1771
-
1772
- {config.visualizationType !== 'Pie' && (
1773
- <>
1774
- <TextField value={config.xAxis.label} section='xAxis' fieldName='label' label='Label' updateField={updateField} />
1730
+ </>
1731
+ )}
1732
+
1733
+ {config.visualizationType === 'Pie' && (
1734
+ <Select
1735
+ value={config.xAxis.dataKey || ''}
1736
+ section='xAxis'
1737
+ fieldName='dataKey'
1738
+ label='Segment Labels'
1739
+ initial='Select'
1740
+ required={true}
1741
+ updateField={updateField}
1742
+ options={getColumns(false)}
1743
+ tooltip={
1744
+ <Tooltip style={{ textTransform: 'none' }}>
1745
+ <Tooltip.Target>
1746
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1747
+ </Tooltip.Target>
1748
+ <Tooltip.Content>
1749
+ <p>Select the source row or column that contains the segment labels. Depending on the data structure, it may be listed as "Key."</p>
1750
+ </Tooltip.Content>
1751
+ </Tooltip>
1752
+ }
1753
+ />
1754
+ )}
1775
1755
 
1776
- {config.xAxis.type === 'continuous' && (
1777
- <>
1778
- <TextField
1779
- value={config.dataFormat.bottomPrefix}
1780
- section='dataFormat'
1781
- fieldName='bottomPrefix'
1782
- label='Prefix'
1783
- updateField={updateField}
1784
- tooltip={
1785
- <Tooltip style={{ textTransform: 'none' }}>
1786
- <Tooltip.Target>
1787
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1788
- </Tooltip.Target>
1789
- <Tooltip.Content>
1790
- <p>Enter a data suffix (such as "%"), if applicable.</p>
1791
- </Tooltip.Content>
1792
- </Tooltip>
1793
- }
1794
- />
1756
+ {config.visualizationType !== 'Pie' && (
1757
+ <>
1758
+ <TextField value={config.xAxis.label} section='xAxis' fieldName='label' label='Label' updateField={updateField} />
1795
1759
 
1796
- <TextField
1797
- value={config.dataFormat.bottomSuffix}
1798
- section='dataFormat'
1799
- fieldName='bottomSuffix'
1800
- label='Suffix'
1801
- updateField={updateField}
1802
- tooltip={
1803
- <Tooltip style={{ textTransform: 'none' }}>
1804
- <Tooltip.Target>
1805
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1806
- </Tooltip.Target>
1807
- <Tooltip.Content>
1808
- <p>Enter a data suffix (such as "%"), if applicable.</p>
1809
- </Tooltip.Content>
1810
- </Tooltip>
1811
- }
1812
- />
1760
+ {config.xAxis.type === 'continuous' && (
1761
+ <>
1762
+ <TextField
1763
+ value={config.dataFormat.bottomPrefix}
1764
+ section='dataFormat'
1765
+ fieldName='bottomPrefix'
1766
+ label='Prefix'
1767
+ updateField={updateField}
1768
+ tooltip={
1769
+ <Tooltip style={{ textTransform: 'none' }}>
1770
+ <Tooltip.Target>
1771
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1772
+ </Tooltip.Target>
1773
+ <Tooltip.Content>
1774
+ <p>Enter a data prefix (such as "$"), if applicable.</p>
1775
+ </Tooltip.Content>
1776
+ </Tooltip>
1777
+ }
1778
+ />
1813
1779
 
1814
- <CheckBox
1815
- value={config.dataFormat.bottomAbbreviated}
1816
- section='dataFormat'
1817
- fieldName='bottomAbbreviated'
1818
- label='Abbreviate Axis Values'
1819
- updateField={updateField}
1820
- tooltip={
1821
- <Tooltip style={{ textTransform: 'none' }}>
1822
- <Tooltip.Target>
1823
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1824
- </Tooltip.Target>
1825
- <Tooltip.Content>
1826
- <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
1827
- </Tooltip.Content>
1828
- </Tooltip>
1829
- }
1830
- />
1831
- </>
1832
- )}
1833
-
1834
- {isDateScale(config.xAxis) && (
1835
- <>
1836
- <p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
1837
- Format how charts should parse and display your dates using{' '}
1838
- <a href='https://github.com/d3/d3-time-format#locale_format' target='_blank' rel='noreferrer'>
1839
- these guidelines
1840
- </a>
1841
- .
1842
- </p>
1843
- <TextField
1844
- tooltip={
1845
- <Tooltip style={{ textTransform: 'none' }}>
1846
- <Tooltip.Target>
1847
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1848
- </Tooltip.Target>
1849
- <Tooltip.Content>
1850
- <p>This field specifies the pattern used to read and interpret dates in your dataset, ensuring the dates are correctly understood and processed. </p>
1851
- </Tooltip.Content>
1852
- </Tooltip>
1853
- }
1854
- value={config.xAxis.dateParseFormat}
1855
- section='xAxis'
1856
- fieldName='dateParseFormat'
1857
- placeholder='Ex. %Y-%m-%d'
1858
- label='Date Parse Format'
1859
- updateField={updateField}
1860
- />
1861
- <TextField
1862
- tooltip={
1863
- <Tooltip style={{ textTransform: 'none' }}>
1864
- <Tooltip.Target>
1865
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1866
- </Tooltip.Target>
1867
- <Tooltip.Content>
1868
- <p> Adjusts the date display format on the axis for clear, visual date representation.</p>
1869
- </Tooltip.Content>
1870
- </Tooltip>
1871
- }
1872
- value={config.xAxis.dateDisplayFormat}
1873
- section='xAxis'
1874
- fieldName='dateDisplayFormat'
1875
- placeholder='Ex. %Y-%m-%d'
1876
- label='AXIS DATE DISPLAY FORMAT'
1877
- updateField={updateField}
1878
- />
1879
- <TextField
1880
- tooltip={
1881
- <Tooltip style={{ textTransform: 'none' }}>
1882
- <Tooltip.Target>
1883
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1884
- </Tooltip.Target>
1885
- <Tooltip.Content>
1886
- <p>Specify a custom format for displaying dates in data table. If left empty, dates will adopt the Axis Date Display format. </p>
1887
- </Tooltip.Content>
1888
- </Tooltip>
1889
- }
1890
- value={config.table.dateDisplayFormat}
1891
- section='table'
1892
- fieldName='dateDisplayFormat'
1893
- placeholder='Ex. %Y-%m-%d'
1894
- label='DATA TABLE DATE DISPLAY FORMAT'
1895
- updateField={updateField}
1896
- />
1897
- <TextField
1898
- tooltip={
1899
- <Tooltip style={{ textTransform: 'none' }}>
1900
- <Tooltip.Target>
1901
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1902
- </Tooltip.Target>
1903
- <Tooltip.Content>
1904
- <p>Specify a custom format for displaying dates on hovers. If left empty, dates will adopt the Axis Date Display format. </p>
1905
- </Tooltip.Content>
1906
- </Tooltip>
1907
- }
1908
- value={config.tooltips.dateDisplayFormat}
1909
- section='tooltips'
1910
- fieldName='dateDisplayFormat'
1911
- placeholder='Ex. %Y-%m-%d'
1912
- label='HOVER DATE DISPLAY FORMAT'
1913
- updateField={updateField}
1914
- />
1915
- </>
1916
- )}
1917
-
1918
- <CheckBox
1919
- value={config.exclusions.active}
1920
- section='exclusions'
1921
- fieldName='active'
1922
- label={config.xAxis.type === 'date' ? 'Limit by start and/or end dates' : 'Exclude one or more values'}
1923
- tooltip={
1924
- <Tooltip style={{ textTransform: 'none' }}>
1925
- <Tooltip.Target>
1926
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1927
- </Tooltip.Target>
1928
- <Tooltip.Content>
1929
- <p>When this option is checked, you can select source-file values for exclusion from the date/category axis. </p>
1930
- </Tooltip.Content>
1931
- </Tooltip>
1932
- }
1933
- updateField={updateField}
1934
- />
1935
- {/* {visHasBrushChart && <CheckBox value={config.brush.active} section='brush' fieldName='active' label='Brush Slider ' updateField={updateField} />} */}
1780
+ <TextField
1781
+ value={config.dataFormat.bottomSuffix}
1782
+ section='dataFormat'
1783
+ fieldName='bottomSuffix'
1784
+ label='Suffix'
1785
+ updateField={updateField}
1786
+ tooltip={
1787
+ <Tooltip style={{ textTransform: 'none' }}>
1788
+ <Tooltip.Target>
1789
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1790
+ </Tooltip.Target>
1791
+ <Tooltip.Content>
1792
+ <p>Enter a data suffix (such as "%"), if applicable.</p>
1793
+ </Tooltip.Content>
1794
+ </Tooltip>
1795
+ }
1796
+ />
1936
1797
 
1937
- {config.exclusions.active && (
1938
- <>
1939
- {config.xAxis.type === 'categorical' && (
1940
- <>
1941
- {config.exclusions.keys.length > 0 && (
1942
- <>
1943
- <fieldset>
1944
- <legend className='edit-label'>Excluded Keys</legend>
1945
- </fieldset>
1946
- <ExclusionsList />
1947
- </>
1948
- )}
1949
-
1950
- <Select
1951
- fieldName='visualizationType'
1952
- label='Add Exclusion'
1953
- initial='Select'
1954
- onChange={e => {
1955
- if (e.target.value !== '' && e.target.value !== 'Select') {
1956
- addNewExclusion(e.target.value)
1957
- }
1958
- e.target.value = ''
1959
- }}
1960
- options={getDataValues(config.xAxis.dataKey, true)}
1961
- />
1962
- </>
1963
- )}
1798
+ <CheckBox
1799
+ value={config.dataFormat.bottomAbbreviated}
1800
+ section='dataFormat'
1801
+ fieldName='bottomAbbreviated'
1802
+ label='Abbreviate Axis Values'
1803
+ updateField={updateField}
1804
+ tooltip={
1805
+ <Tooltip style={{ textTransform: 'none' }}>
1806
+ <Tooltip.Target>
1807
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1808
+ </Tooltip.Target>
1809
+ <Tooltip.Content>
1810
+ <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
1811
+ </Tooltip.Content>
1812
+ </Tooltip>
1813
+ }
1814
+ />
1815
+ </>
1816
+ )}
1964
1817
 
1965
- {config.xAxis.type === 'date' && (
1966
- <>
1967
- <TextField type='date' section='exclusions' fieldName='dateStart' label='Start Date' updateField={updateField} value={config.exclusions.dateStart || ''} />
1968
- <TextField type='date' section='exclusions' fieldName='dateEnd' label='End Date' updateField={updateField} value={config.exclusions.dateEnd || ''} />
1969
- </>
1970
- )}
1971
- </>
1972
- )}
1973
-
1974
- {visSupportsDateCategoryNumTicks() && <TextField value={config.xAxis.numTicks} placeholder='Auto' type='number' min={1} section='xAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />}
1975
- {visSupportsDateCategoryHeight() && <TextField value={config.xAxis.size} type='number' min={0} section='xAxis' fieldName='size' label={config.orientation === 'horizontal' ? 'Size (Width)' : 'Size (Height)'} className='number-narrow' updateField={updateField} />}
1976
-
1977
- {visSupportsDateCategoryAxisPadding() && <TextField value={config.xAxis.padding} type='number' min={0} section='xAxis' fieldName='padding' label={'Padding (Percent)'} className='number-narrow' updateField={updateField} />}
1978
-
1979
- {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
1980
- {/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
1981
- {(config.xAxis.type === 'continuous' || config.forestPlot.type === 'Logarithmic') && (
1982
- <>
1983
- <CheckBox value={config.dataFormat.bottomCommas} section='dataFormat' fieldName='bottomCommas' label='Add commas' updateField={updateField} />
1984
- <TextField value={config.dataFormat.bottomRoundTo} type='number' section='dataFormat' fieldName='bottomRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1985
- </>
1986
- )}
1987
- {visSupportsResponsiveTicks() && config.orientation === 'vertical' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
1988
- {(config.orientation === 'horizontal' || !config.isResponsiveTicks) && visSupportsDateCategoryTickRotation() && (
1989
- <TextField value={config.xAxis.tickRotation} type='number' min={0} section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />
1990
- )}
1991
- {config.orientation === 'vertical' && config.isResponsiveTicks && config.visualizationType !== 'Paired Bar' && (
1818
+ {isDateScale(config.xAxis) && (
1819
+ <>
1820
+ <p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
1821
+ Format how charts should parse and display your dates using{' '}
1822
+ <a href='https://github.com/d3/d3-time-format#locale_format' target='_blank' rel='noreferrer'>
1823
+ these guidelines
1824
+ </a>
1825
+ .
1826
+ </p>
1992
1827
  <TextField
1993
- value={config.xAxis.maxTickRotation}
1994
- type='number'
1995
- min={0}
1828
+ tooltip={
1829
+ <Tooltip style={{ textTransform: 'none' }}>
1830
+ <Tooltip.Target>
1831
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1832
+ </Tooltip.Target>
1833
+ <Tooltip.Content>
1834
+ <p>This field specifies the pattern used to read and interpret dates in your dataset, ensuring the dates are correctly understood and processed. </p>
1835
+ </Tooltip.Content>
1836
+ </Tooltip>
1837
+ }
1838
+ value={config.xAxis.dateParseFormat}
1996
1839
  section='xAxis'
1997
- fieldName='maxTickRotation'
1998
- label='Max Tick Rotation'
1999
- className='number-narrow'
1840
+ fieldName='dateParseFormat'
1841
+ placeholder='Ex. %Y-%m-%d'
1842
+ label='Date Parse Format'
2000
1843
  updateField={updateField}
1844
+ />
1845
+ <TextField
2001
1846
  tooltip={
2002
1847
  <Tooltip style={{ textTransform: 'none' }}>
2003
1848
  <Tooltip.Target>
2004
1849
  <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2005
1850
  </Tooltip.Target>
2006
1851
  <Tooltip.Content>
2007
- <p>Degrees ticks will be rotated if values overlap, especially in smaller viewports.</p>
1852
+ <p> Adjusts the date display format on the axis for clear, visual date representation.</p>
2008
1853
  </Tooltip.Content>
2009
1854
  </Tooltip>
2010
1855
  }
1856
+ value={config.xAxis.dateDisplayFormat}
1857
+ section='xAxis'
1858
+ fieldName='dateDisplayFormat'
1859
+ placeholder='Ex. %Y-%m-%d'
1860
+ label='AXIS DATE DISPLAY FORMAT'
1861
+ updateField={updateField}
2011
1862
  />
2012
- )}
2013
-
2014
- {config.orientation === 'horizontal' ? (
2015
- <>
2016
- {visSupportsDateCategoryAxisLine() && <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2017
- {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
2018
- </>
2019
- ) : (
2020
- <>
2021
- {visSupportsDateCategoryAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2022
- {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
2023
- {visSupportsDateCategoryAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
2024
- </>
2025
- )}
2026
-
2027
- {config.series?.length === 1 && config.visualizationType === 'Bar' && (
2028
- <>
2029
- {/* HIGHLIGHTED BARS */}
2030
- <label htmlFor='barHighlight'>Bar Highlighting</label>
2031
- {config.series.length === 1 &&
2032
- highlightedBarValues.map((highlightedBarValue, i) => (
2033
- <fieldset>
2034
- <div className='edit-block' key={`highlighted-bar-${i}`}>
2035
- <button className='remove-column' onClick={e => handleRemoveHighlightedBar(e, i)}>
2036
- Remove
2037
- </button>
2038
- <p>Highlighted Bar {i + 1}</p>
2039
- <label>
2040
- <span className='edit-label column-heading'>Value</span>
2041
- <select value={config.highlightedBarValues[i].value} onChange={e => handleUpdateHighlightedBar(e, i)}>
2042
- <option value=''>- Select Value -</option>
2043
- {highlightedSeriesValues && [...new Set(highlightedSeriesValues)].sort().map(option => <option key={`special-class-value-option-${i}-${option}`}>{option}</option>)}
2044
- </select>
2045
- </label>
2046
- <label>
2047
- <span className='edit-label column-heading'>Color</span>
2048
- <input type='text' value={config.highlightedBarValues[i].color ? config.highlightedBarValues[i].color : ''} onChange={e => handleUpdateHighlightedBarColor(e, i)} />
2049
- </label>
2050
- <label>
2051
- <span className='edit-label column-heading'>Border Width</span>
2052
- <input max='5' min='0' type='number' value={config.highlightedBarValues[i].borderWidth ? config.highlightedBarValues[i].borderWidth : ''} onChange={e => handleUpdateHighlightedBorderWidth(e, i)} />
2053
- </label>
2054
- <label>
2055
- <span className='edit-label column-heading'>Legend Label</span>
2056
- <input type='text' value={config.highlightedBarValues[i].legendLabel ? config.highlightedBarValues[i].legendLabel : ''} onChange={e => handleHighlightedBarLegendLabel(e, i)} />
2057
- </label>
2058
- </div>
2059
- </fieldset>
2060
- ))}
2061
- <button className='btn full-width' onClick={e => handleAddNewHighlightedBar(e)}>
2062
- Add Highlighted Bar
2063
- </button>
2064
- </>
2065
- )}
2066
- </>
2067
- )}
2068
-
2069
- {config.visualizationType === 'Pie' && (
2070
- <>
2071
- <CheckBox
2072
- value={config.exclusions.active}
2073
- section='exclusions'
2074
- fieldName='active'
2075
- label={'Exclude one or more values'}
2076
- updateField={updateField}
2077
- tooltip={
2078
- <Tooltip style={{ textTransform: 'none' }}>
2079
- <Tooltip.Target>
2080
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2081
- </Tooltip.Target>
2082
- <Tooltip.Content>
2083
- <p>When this option is checked, you can select values for exclusion from the pie segments.</p>
2084
- </Tooltip.Content>
2085
- </Tooltip>
2086
- }
2087
- />
2088
- {config.exclusions.active && (
2089
- <>
2090
- {config.exclusions.keys.length > 0 && (
2091
- <>
2092
- <fieldset>
2093
- <legend className='edit-label'>Excluded Keys</legend>
2094
- </fieldset>
2095
- <ExclusionsList />
2096
- </>
2097
- )}
2098
-
2099
- <Select
2100
- fieldName='visualizationType'
2101
- label='Add Exclusion'
2102
- initial='Select'
2103
- onChange={e => {
2104
- if (e.target.value !== '' && e.target.value !== 'Select') {
2105
- addNewExclusion(e.target.value)
2106
- }
2107
- e.target.value = ''
2108
- }}
2109
- options={getDataValues(config.xAxis.dataKey, true)}
2110
- />
2111
- </>
2112
- )}
2113
- </>
2114
- )}
2115
-
2116
- {/* anchors */}
2117
- {visHasAnchors() && config.orientation !== 'horizontal' && (
2118
- <div className='edit-block'>
2119
- <span className='edit-label column-heading'>Anchors</span>
2120
- <Accordion allowZeroExpanded>
2121
- {config.xAxis?.anchors?.map((anchor, index) => (
2122
- <AccordionItem className='series-item series-item--chart' key={`xaxis-anchors-2-${index}`}>
2123
- <AccordionItemHeading className='series-item__title'>
2124
- <>
2125
- <AccordionItemButton className={'accordion__button accordion__button'}>
2126
- Anchor {index + 1}
2127
- <button
2128
- className='series-list__remove'
2129
- onClick={e => {
2130
- e.preventDefault()
2131
- const copiedAnchorGroups = [...config.xAxis.anchors]
2132
- copiedAnchorGroups.splice(index, 1)
2133
- updateConfig({
2134
- ...config,
2135
- xAxis: {
2136
- ...config.xAxis,
2137
- anchors: copiedAnchorGroups
2138
- }
2139
- })
2140
- }}
2141
- >
2142
- Remove
2143
- </button>
2144
- </AccordionItemButton>
2145
- </>
2146
- </AccordionItemHeading>
2147
- <AccordionItemPanel>
2148
- <label>
2149
- <span>Anchor Value</span>
2150
- <Tooltip style={{ textTransform: 'none' }}>
2151
- <Tooltip.Target>
2152
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2153
- </Tooltip.Target>
2154
- <Tooltip.Content>
2155
- <p>Enter the value as its shown in the data column</p>
2156
- </Tooltip.Content>
2157
- </Tooltip>
2158
- <input
2159
- type='text'
2160
- value={config.xAxis.anchors[index].value ? config.xAxis.anchors[index].value : ''}
2161
- onChange={e => {
2162
- e.preventDefault()
2163
- const copiedAnchors = [...config.xAxis.anchors]
2164
- copiedAnchors[index].value = e.target.value
2165
- updateConfig({
2166
- ...config,
2167
- xAxis: {
2168
- ...config.xAxis,
2169
- anchors: copiedAnchors
2170
- }
2171
- })
2172
- }}
2173
- />
2174
- </label>
2175
-
2176
- <label>
2177
- <span>Anchor Color</span>
2178
- <input
2179
- type='text'
2180
- value={config.xAxis.anchors[index].color ? config.xAxis.anchors[index].color : ''}
2181
- onChange={e => {
2182
- e.preventDefault()
2183
- const copiedAnchors = [...config.xAxis.anchors]
2184
- copiedAnchors[index].color = e.target.value
2185
- updateConfig({
2186
- ...config,
2187
- xAxis: {
2188
- ...config.xAxis,
2189
- anchors: copiedAnchors
2190
- }
2191
- })
2192
- }}
2193
- />
2194
- </label>
2195
-
2196
- <label>
2197
- Anchor Line Style
2198
- <select
2199
- value={config.xAxis.anchors[index].lineStyle || ''}
2200
- onChange={e => {
2201
- const copiedAnchors = [...config.xAxis.anchors]
2202
- copiedAnchors[index].lineStyle = e.target.value
2203
- updateConfig({
2204
- ...config,
2205
- xAxis: {
2206
- ...config.xAxis,
2207
- anchors: copiedAnchors
2208
- }
2209
- })
2210
- }}
2211
- >
2212
- <option>Select</option>
2213
- {lineOptions.map(line => (
2214
- <option key={line.key}>{line.value}</option>
2215
- ))}
2216
- </select>
2217
- </label>
2218
- </AccordionItemPanel>
2219
- </AccordionItem>
2220
- ))}
2221
- </Accordion>
2222
-
2223
- <button
2224
- className='btn full-width'
2225
- onClick={e => {
2226
- e.preventDefault()
2227
- const anchors = [...config.xAxis.anchors]
2228
- anchors.push({} as Anchor)
2229
- updateConfig({
2230
- ...config,
2231
- xAxis: {
2232
- ...config.xAxis,
2233
- anchors
2234
- }
2235
- })
2236
- }}
2237
- >
2238
- Add Anchor
2239
- </button>
2240
- </div>
2241
- )}
2242
-
2243
- {visHasAnchors() && config.orientation === 'horizontal' && (
2244
- <div className='edit-block'>
2245
- <span className='edit-label column-heading'>Anchors</span>
2246
- <Accordion allowZeroExpanded>
2247
- {config.yAxis?.anchors?.map((anchor, index) => (
2248
- <AccordionItem className='series-item series-item--chart' key={`accordion-yaxis-anchors-${index}`}>
2249
- <AccordionItemHeading className='series-item__title'>
2250
- <>
2251
- <AccordionItemButton className={'accordion__button accordion__button'}>
2252
- Anchor {index + 1}
2253
- <button
2254
- className='series-list__remove'
2255
- onClick={e => {
2256
- e.preventDefault()
2257
- const copiedAnchorGroups = [...config.yAxis.anchors]
2258
- copiedAnchorGroups.splice(index, 1)
2259
- updateConfig({
2260
- ...config,
2261
- yAxis: {
2262
- ...config.yAxis,
2263
- anchors: copiedAnchorGroups
2264
- }
2265
- })
2266
- }}
2267
- >
2268
- Remove
2269
- </button>
2270
- </AccordionItemButton>
2271
- </>
2272
- </AccordionItemHeading>
2273
- <AccordionItemPanel>
2274
- <label>
2275
- <span>Anchor Value</span>
2276
- <Tooltip style={{ textTransform: 'none' }}>
2277
- <Tooltip.Target>
2278
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2279
- </Tooltip.Target>
2280
- <Tooltip.Content>
2281
- <p>Enter the value as its shown in the data column</p>
2282
- </Tooltip.Content>
2283
- </Tooltip>
2284
- <input
2285
- type='text'
2286
- value={config.yAxis.anchors[index].value ? config.yAxis.anchors[index].value : ''}
2287
- onChange={e => {
2288
- e.preventDefault()
2289
- const copiedAnchors = [...config.yAxis.anchors]
2290
- copiedAnchors[index].value = e.target.value
2291
- updateConfig({
2292
- ...config,
2293
- yAxis: {
2294
- ...config.yAxis,
2295
- anchors: copiedAnchors
2296
- }
2297
- })
2298
- }}
2299
- />
2300
- </label>
2301
-
2302
- <label>
2303
- <span>Anchor Color</span>
2304
- <input
2305
- type='text'
2306
- value={config.yAxis.anchors[index].color ? config.yAxis.anchors[index].color : ''}
2307
- onChange={e => {
2308
- e.preventDefault()
2309
- const copiedAnchors = [...config.yAxis.anchors]
2310
- copiedAnchors[index].color = e.target.value
2311
- updateConfig({
2312
- ...config,
2313
- yAxis: {
2314
- ...config.yAxis,
2315
- anchors: copiedAnchors
2316
- }
2317
- })
2318
- }}
2319
- />
2320
- </label>
2321
-
2322
- <label>
2323
- Anchor Line Style
2324
- <select
2325
- value={config.yAxis.anchors[index].lineStyle || ''}
2326
- onChange={e => {
2327
- const copiedAnchors = [...config.yAxis.anchors]
2328
- copiedAnchors[index].lineStyle = e.target.value
2329
- updateConfig({
2330
- ...config,
2331
- yAxis: {
2332
- ...config.yAxis,
2333
- anchors: copiedAnchors
2334
- }
2335
- })
2336
- }}
2337
- >
2338
- <option>Select</option>
2339
- {lineOptions.map(line => (
2340
- <option key={line.key}>{line.value}</option>
2341
- ))}
2342
- </select>
2343
- </label>
2344
- </AccordionItemPanel>
2345
- </AccordionItem>
2346
- ))}
2347
- </Accordion>
2348
-
2349
- <button
2350
- className='btn full-width'
2351
- onClick={e => {
2352
- e.preventDefault()
2353
- const anchors = [...config.yAxis.anchors]
2354
- anchors.push({} as Anchor)
2355
- updateConfig({
2356
- ...config,
2357
- yAxis: {
2358
- ...config.yAxis,
2359
- anchors
2360
- }
2361
- })
2362
- }}
2363
- >
2364
- Add Anchor
2365
- </button>
2366
- </div>
2367
- )}
2368
- </AccordionItemPanel>
2369
- </AccordionItem>
2370
- )}
2371
- <Panels.Regions name='Regions' />
2372
- {/* Columns */}
2373
- {config.visualizationType !== 'Box Plot' && (
2374
- <AccordionItem>
2375
- <AccordionItemHeading>
2376
- <AccordionItemButton>Columns</AccordionItemButton>
2377
- </AccordionItemHeading>
2378
- <AccordionItemPanel>
2379
- {'navigation' !== config.type && (
2380
- <fieldset className='primary-fieldset edit-block'>
2381
- <label>
2382
- <span className='edit-label'>
2383
- Additional Columns
2384
- <Tooltip style={{ textTransform: 'none' }}>
2385
- <Tooltip.Target>
2386
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2387
- </Tooltip.Target>
2388
- <Tooltip.Content>
2389
- <p>You can specify additional columns to display in tooltips and / or the supporting data table.</p>
2390
- </Tooltip.Content>
2391
- </Tooltip>
2392
- </span>
2393
- </label>
2394
- {additionalColumns.map(val => (
2395
- <fieldset className='edit-block' key={val}>
2396
- <button
2397
- className='remove-column'
2398
- onClick={event => {
2399
- event.preventDefault()
2400
- removeAdditionalColumn(val)
2401
- }}
2402
- >
2403
- Remove
2404
- </button>
2405
- <label>
2406
- <span className='edit-label column-heading'>Column</span>
2407
- <select
2408
- value={config.columns[val] ? config.columns[val].name : getColumns()[0]}
2409
- onChange={event => {
2410
- editColumn(val, 'name', event.target.value)
2411
- }}
2412
- >
2413
- {getColumns().map(option => (
2414
- <option>{option}</option>
2415
- ))}
2416
- </select>
2417
- </label>
2418
- <label>
2419
- <span className='edit-label column-heading'>Associate to Series</span>
2420
- <select
2421
- value={config.columns[val] ? config.columns[val].series : ''}
2422
- onChange={event => {
2423
- editColumn(val, 'series', event.target.value)
2424
- }}
2425
- >
2426
- <option value=''>Select series</option>
2427
- {config.series.map(series => (
2428
- <option>{series.dataKey}</option>
2429
- ))}
2430
- </select>
2431
- </label>
2432
- <TextField value={config.columns[val].label} section='columns' subsection={val} fieldName='label' label='Label' updateField={updateField} />
2433
- <ul className='column-edit'>
2434
- <li className='three-col'>
2435
- <TextField value={config.columns[val].prefix} section='columns' subsection={val} fieldName='prefix' label='Prefix' updateField={updateField} />
2436
- <TextField value={config.columns[val].suffix} section='columns' subsection={val} fieldName='suffix' label='Suffix' updateField={updateField} />
2437
- <TextField type='number' value={config.columns[val].roundToPlace} section='columns' subsection={val} fieldName='roundToPlace' label='Round' updateField={updateField} />
2438
- </li>
2439
- <li>
2440
- <label className='checkbox'>
2441
- <input
2442
- type='checkbox'
2443
- checked={config.columns[val].commas}
2444
- onChange={event => {
2445
- editColumn(val, 'commas', event.target.checked)
2446
- }}
2447
- />
2448
- <span className='edit-label'>Add Commas to Numbers</span>
2449
- </label>
2450
- </li>
2451
- <li>
2452
- {config.table.showVertical && (
2453
- <label className='checkbox'>
2454
- <input
2455
- type='checkbox'
2456
- checked={config.columns[val].dataTable}
2457
- onChange={event => {
2458
- editColumn(val, 'dataTable', event.target.checked)
2459
- }}
2460
- />
2461
- <span className='edit-label'>Show in Data Table</span>
2462
- </label>
2463
- )}
2464
- </li>
2465
- {config.visualizationType === 'Pie' && (
2466
- <li>
2467
- <label className='checkbox'>
2468
- <input
2469
- type='checkbox'
2470
- checked={config.columns[val].showInViz}
2471
- onChange={event => {
2472
- editColumn(val, 'showInViz', event.target.checked)
2473
- }}
2474
- />
2475
- <span className='edit-label'>Show in Visualization</span>
2476
- </label>
2477
- </li>
2478
- )}
2479
-
2480
- {/* disable for now */}
1863
+ <TextField
1864
+ tooltip={
1865
+ <Tooltip style={{ textTransform: 'none' }}>
1866
+ <Tooltip.Target>
1867
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1868
+ </Tooltip.Target>
1869
+ <Tooltip.Content>
1870
+ <p>Specify a custom format for displaying dates in data table. If left empty, dates will adopt the Axis Date Display format. </p>
1871
+ </Tooltip.Content>
1872
+ </Tooltip>
1873
+ }
1874
+ value={config.table.dateDisplayFormat}
1875
+ section='table'
1876
+ fieldName='dateDisplayFormat'
1877
+ placeholder='Ex. %Y-%m-%d'
1878
+ label='DATA TABLE DATE DISPLAY FORMAT'
1879
+ updateField={updateField}
1880
+ />
1881
+ <TextField
1882
+ tooltip={
1883
+ <Tooltip style={{ textTransform: 'none' }}>
1884
+ <Tooltip.Target>
1885
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1886
+ </Tooltip.Target>
1887
+ <Tooltip.Content>
1888
+ <p>Specify a custom format for displaying dates on hovers. If left empty, dates will adopt the Axis Date Display format. </p>
1889
+ </Tooltip.Content>
1890
+ </Tooltip>
1891
+ }
1892
+ value={config.tooltips.dateDisplayFormat}
1893
+ section='tooltips'
1894
+ fieldName='dateDisplayFormat'
1895
+ placeholder='Ex. %Y-%m-%d'
1896
+ label='HOVER DATE DISPLAY FORMAT'
1897
+ updateField={updateField}
1898
+ />
1899
+ </>
1900
+ )}
2481
1901
 
2482
- <li>
2483
- <label className='checkbox'>
2484
- <input
2485
- type='checkbox'
2486
- checked={config.columns[val].tooltips || false}
2487
- onChange={event => {
2488
- updateSeriesTooltip(val, event.target.checked)
2489
- }}
2490
- />
2491
- <span className='edit-label'>Show in tooltip</span>
2492
- </label>
2493
- </li>
1902
+ <CheckBox
1903
+ value={config.exclusions.active}
1904
+ section='exclusions'
1905
+ fieldName='active'
1906
+ label={config.xAxis.type === 'date' ? 'Limit by start and/or end dates' : 'Exclude one or more values'}
1907
+ tooltip={
1908
+ <Tooltip style={{ textTransform: 'none' }}>
1909
+ <Tooltip.Target>
1910
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1911
+ </Tooltip.Target>
1912
+ <Tooltip.Content>
1913
+ <p>When this option is checked, you can select source-file values for exclusion from the date/category axis. </p>
1914
+ </Tooltip.Content>
1915
+ </Tooltip>
1916
+ }
1917
+ updateField={updateField}
1918
+ />
1919
+ {/* {visHasBrushChart && <CheckBox value={config.brush.active} section='brush' fieldName='active' label='Brush Slider ' updateField={updateField} />} */}
2494
1920
 
2495
- {config.visualizationType === 'Forest Plot' && (
1921
+ {config.exclusions.active && (
1922
+ <>
1923
+ {config.xAxis.type === 'categorical' && (
1924
+ <>
1925
+ {config.exclusions.keys.length > 0 && (
2496
1926
  <>
2497
- <li>
2498
- <label className='checkbox'>
2499
- <input
2500
- type='checkbox'
2501
- checked={config.columns[val].forestPlot || false}
2502
- onChange={event => {
2503
- editColumn(val, 'forestPlot', event.target.checked)
2504
- }}
2505
- />
2506
- <span className='edit-label'>Show in Forest Plot</span>
2507
- </label>
2508
- </li>
2509
- <li>
2510
- <label className='checkbox'>
2511
- <input
2512
- type='checkbox'
2513
- checked={config.columns[val].forestPlotAlignRight || false}
2514
- onChange={event => {
2515
- editColumn(val, 'forestPlotAlignRight', event.target.checked)
2516
- }}
2517
- />
2518
- <span className='edit-label'>Align Right</span>
2519
- </label>
2520
- </li>
2521
-
2522
- {!config.columns[val].forestPlotAlignRight && (
2523
- <li>
2524
- <label className='text'>
2525
- <span className='edit-label'>Forest Plot Starting Point</span>
2526
- <input
2527
- type='number'
2528
- value={config.columns[val].forestPlotStartingPoint || 0}
2529
- onChange={event => {
2530
- editColumn(val, 'forestPlotStartingPoint', event.target.value)
2531
- }}
2532
- />
2533
- </label>
2534
- </li>
2535
- )}
1927
+ <fieldset>
1928
+ <legend className='edit-label'>Excluded Keys</legend>
1929
+ </fieldset>
1930
+ <ExclusionsList />
2536
1931
  </>
2537
1932
  )}
2538
- </ul>
2539
- </fieldset>
2540
- ))}
2541
- <button
2542
- className={'btn full-width'}
2543
- onClick={event => {
2544
- event.preventDefault()
2545
- addAdditionalColumn(additionalColumns.length + 1)
2546
- }}
2547
- >
2548
- Add Column
2549
- </button>
2550
- </fieldset>
2551
- )}
2552
- {'category' === config.legend.type && (
2553
- <fieldset className='primary-fieldset edit-block'>
2554
- <label>
2555
- <span className='edit-label'>
2556
- Additional Category
2557
- <Tooltip style={{ textTransform: 'none' }}>
2558
- <Tooltip.Target>
2559
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2560
- </Tooltip.Target>
2561
- <Tooltip.Content>
2562
- <p>You can provide additional categories to ensure they appear in the legend</p>
2563
- </Tooltip.Content>
2564
- </Tooltip>
2565
- </span>
2566
- </label>
2567
- {config.legend.additionalCategories &&
2568
- config.legend.additionalCategories.map((val, i) => (
2569
- <fieldset className='edit-block' key={val}>
2570
- <button
2571
- className='remove-column'
2572
- onClick={event => {
2573
- event.preventDefault()
2574
- const updatedAdditionaCategories = [...config.legend.additionalCategories]
2575
- updatedAdditionaCategories.splice(i, 1)
2576
- updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2577
- }}
2578
- >
2579
- Remove
2580
- </button>
2581
- <TextField
2582
- value={val}
2583
- label='Category'
2584
- section='legend'
2585
- subsection={null}
2586
- fieldName='additionalCategories'
2587
- updateField={(section, subsection, fieldName, value) => {
2588
- const updatedAdditionaCategories = [...config.legend.additionalCategories]
2589
- updatedAdditionaCategories[i] = value
2590
- updateField(section, subsection, fieldName, updatedAdditionaCategories)
1933
+
1934
+ <Select
1935
+ fieldName='visualizationType'
1936
+ label='Add Exclusion'
1937
+ initial='Select'
1938
+ onChange={e => {
1939
+ if (e.target.value !== '' && e.target.value !== 'Select') {
1940
+ addNewExclusion(e.target.value)
1941
+ }
1942
+ e.target.value = ''
2591
1943
  }}
1944
+ options={getDataValues(config.xAxis.dataKey, true)}
2592
1945
  />
2593
- </fieldset>
2594
- ))}
2595
- <button
2596
- className={'btn full-width'}
2597
- onClick={event => {
2598
- event.preventDefault()
2599
- const updatedAdditionaCategories = [...(config.legend.additionalCategories || [])]
2600
- updatedAdditionaCategories.push('')
2601
- updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2602
- }}
2603
- >
2604
- Add Category
2605
- </button>
2606
- </fieldset>
2607
- )}
2608
- </AccordionItemPanel>
2609
- </AccordionItem>
2610
- )}
2611
- {/* End Columns */}
2612
- {visHasLegend() && (
2613
- <AccordionItem>
2614
- <AccordionItemHeading>
2615
- <AccordionItemButton>Legend</AccordionItemButton>
2616
- </AccordionItemHeading>
2617
- <AccordionItemPanel>
2618
- <CheckBox value={config.legend.reverseLabelOrder} section='legend' fieldName='reverseLabelOrder' label='Reverse Labels' updateField={updateField} />
2619
- {/* <fieldset className="checkbox-group">
2620
- <CheckBox value={config.legend.dynamicLegend} section="legend" fieldName="dynamicLegend" label="Dynamic Legend" updateField={updateField}/>
2621
- {config.legend.dynamicLegend && (
2622
- <>
2623
- <TextField value={config.legend.dynamicLegendDefaultText} section="legend" fieldName="dynamicLegendDefaultText" label="Dynamic Legend Default Text" updateField={updateField} />
2624
- <TextField value={config.legend.dynamicLegendItemLimit} type="number" min="0" section="legend" fieldName="dynamicLegendItemLimit" label={'Dynamic Legend Limit'} className="number-narrow" updateField={updateField}/>
2625
- <TextField value={config.legend.dynamicLegendItemLimitMessage} section="legend" fieldName="dynamicLegendItemLimitMessage" label="Dynamic Legend Item Limit Message" updateField={updateField} />
2626
- <TextField value={config.legend.dynamicLegendChartMessage} section="legend" fieldName="dynamicLegendChartMessage" label="Dynamic Legend Chart Message" updateField={updateField} />
2627
- </>
2628
- )}
2629
- </fieldset> */}
2630
- <CheckBox
2631
- value={config.legend.hide ? true : false}
2632
- section='legend'
2633
- fieldName='hide'
2634
- label='Hide Legend'
2635
- updateField={updateField}
2636
- tooltip={
2637
- <Tooltip style={{ textTransform: 'none' }}>
2638
- <Tooltip.Target>
2639
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2640
- </Tooltip.Target>
2641
- <Tooltip.Content>
2642
- <p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
2643
- </Tooltip.Content>
2644
- </Tooltip>
2645
- }
2646
- />
2647
- {/* {config.visualizationType === 'Box Plot' &&
2648
- <>
2649
- <CheckBox value={config.boxplot.legend.displayHowToReadText} fieldName='displayHowToReadText' section='boxplot' subsection='legend' label='Display How To Read Text' updateField={updateField} />
2650
- <TextField type='textarea' value={config.boxplot.legend.howToReadText} updateField={updateField} fieldName='howToReadText' section='boxplot' subsection='legend' label='How to read text' />
2651
- </>
2652
- } */}
2653
- {config.visualizationType === 'Line' && <CheckBox value={config.legend.lineMode} section='legend' fieldName='lineMode' label='Show Lined Style Legend' updateField={updateField} />}
2654
- {config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1 && (
2655
- <Select value={config.legend.colorCode} section='legend' fieldName='colorCode' label='Color code by category' initial='Select' updateField={updateField} options={getDataValueOptions(data)} />
2656
- )}
2657
- <Select value={config.legend.behavior} section='legend' fieldName='behavior' label='Legend Behavior (When clicked)' updateField={(...[section, , fieldName, value]) => updateBehavior(section, fieldName, value)} options={['highlight', 'isolate']} />
2658
- {visHasLegendAxisAlign() && <CheckBox value={config.legend.axisAlign} fieldName='axisAlign' section='legend' label='Align to Axis on Isolate' updateField={updateField} />}
1946
+ </>
1947
+ )}
1948
+
1949
+ {config.xAxis.type === 'date' && (
1950
+ <>
1951
+ <TextField type='date' section='exclusions' fieldName='dateStart' label='Start Date' updateField={updateField} value={config.exclusions.dateStart || ''} />
1952
+ <TextField type='date' section='exclusions' fieldName='dateEnd' label='End Date' updateField={updateField} value={config.exclusions.dateEnd || ''} />
1953
+ </>
1954
+ )}
1955
+ </>
1956
+ )}
2659
1957
 
2660
- {config.legend.behavior === 'highlight' && config.tooltips.singleSeries && <CheckBox value={config.legend.highlightOnHover} section='legend' fieldName='highlightOnHover' label='HIGHLIGHT DATA SERIES ON HOVER' updateField={updateField} />}
1958
+ {visSupportsDateCategoryNumTicks() && config.xAxis.type !== 'date-time' && config.xAxis.manual && (
1959
+ <TextField value={config.xAxis.manualStep} placeholder='Auto' type='number' min={1} section='xAxis' fieldName='manualStep' label='Step count' className='number-narrow' updateField={updateField} />
1960
+ )}
1961
+ {visSupportsDateCategoryNumTicks() && (config.xAxis.type === 'date-time' || !config.xAxis.manual) && (
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} />
1963
+ )}
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} />}
2661
1965
 
2662
- {/* start: isolated values */}
2663
- {visHasSelectableLegendValues && config.legend.behavior === 'isolate' && !colorCodeByCategory && (
2664
- <fieldset className='primary-fieldset edit-block' key={'additional-highlight-values'}>
2665
- <label>
2666
- <span className='edit-label'>
2667
- Isolate Data Series
1966
+ {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
1967
+ {/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
1968
+ {(config.xAxis.type === 'continuous' || config.forestPlot.type === 'Logarithmic') && (
1969
+ <>
1970
+ <CheckBox value={config.dataFormat.bottomCommas} section='dataFormat' fieldName='bottomCommas' label='Add commas' updateField={updateField} />
1971
+ <TextField value={config.dataFormat.bottomRoundTo} type='number' section='dataFormat' fieldName='bottomRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1972
+ </>
1973
+ )}
1974
+ {visSupportsResponsiveTicks() && config.orientation === 'vertical' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
1975
+ {(config.orientation === 'horizontal' || !config.isResponsiveTicks) && visSupportsDateCategoryTickRotation() && (
1976
+ <TextField value={config.xAxis.tickRotation} type='number' min={0} section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />
1977
+ )}
1978
+ {config.orientation === 'vertical' && config.isResponsiveTicks && config.visualizationType !== 'Paired Bar' && (
1979
+ <TextField
1980
+ value={config.xAxis.maxTickRotation}
1981
+ type='number'
1982
+ min={0}
1983
+ section='xAxis'
1984
+ fieldName='maxTickRotation'
1985
+ label='Max Tick Rotation'
1986
+ className='number-narrow'
1987
+ updateField={updateField}
1988
+ tooltip={
2668
1989
  <Tooltip style={{ textTransform: 'none' }}>
2669
1990
  <Tooltip.Target>
2670
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1991
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2671
1992
  </Tooltip.Target>
2672
1993
  <Tooltip.Content>
2673
- <p>You can choose data series that are shown on load. Others will be added when the user clicks on them in the legend.</p>
1994
+ <p>Degrees ticks will be rotated if values overlap, especially in smaller viewports.</p>
2674
1995
  </Tooltip.Content>
2675
1996
  </Tooltip>
2676
- </span>
2677
- </label>
2678
- {config.legend.seriesHighlight &&
2679
- config.legend.seriesHighlight.map((val, i) => (
2680
- <fieldset className='edit-block' key={`${val}-${i}`}>
2681
- <button
2682
- className='remove-column'
2683
- onClick={event => {
2684
- event.preventDefault()
2685
- const updatedSeriesHighlight = [...config.legend.seriesHighlight]
2686
- updatedSeriesHighlight.splice(i, 1)
2687
- updateField('legend', null, 'seriesHighlight', updatedSeriesHighlight)
2688
- if (!updatedSeriesHighlight.length) {
2689
- highlightReset()
2690
- }
2691
- }}
2692
- >
2693
- Remove
2694
- </button>
2695
- <Select
2696
- value={config.legend.seriesHighlight[i]}
2697
- fieldName='seriesHighlight'
2698
- label='Isolate Value'
2699
- onChange={e => {
2700
- const updatedSeriesHighlight = [...config.legend.seriesHighlight]
2701
- if (!updatedSeriesHighlight.includes(e.target.value)) {
2702
- updatedSeriesHighlight[i] = e.target.value
2703
- updateSeriesIsolateValues([...updatedSeriesHighlight])
2704
- }
2705
- }}
2706
- options={getLegendColumns()}
2707
- />
2708
- </fieldset>
2709
- ))}
2710
- <button
2711
- className={'btn full-width'}
2712
- onClick={event => {
2713
- event.preventDefault()
2714
- const legendColumns = getLegendColumns()
2715
- const updatedSeriesHighlight = [...config.legend.seriesHighlight]
2716
- const seriesLength = updatedSeriesHighlight.length
2717
- if (seriesLength < legendColumns.length) {
2718
- const [newSeriesHighlight] = legendColumns.filter(d => !updatedSeriesHighlight.includes(d))
2719
- updatedSeriesHighlight.push(newSeriesHighlight)
2720
- updateSeriesIsolateValues([...updatedSeriesHighlight])
2721
- }
2722
- }}
2723
- >
2724
- Add Isolate Value
2725
- </button>
2726
- </fieldset>
2727
- )}
2728
- {/* end: isolated values */}
1997
+ }
1998
+ />
1999
+ )}
2729
2000
 
2730
- <TextField value={config.legend.label} section='legend' fieldName='label' label='Title' updateField={updateField} />
2731
- <Select value={config.legend.position} section='legend' fieldName='position' label='Position' updateField={updateField} options={['right', 'left', 'bottom']} />
2732
- {config.legend.position === 'bottom' && (
2733
- <>
2734
- <CheckBox value={config.legend.singleRow} section='legend' fieldName='singleRow' label='Single Row Legend' updateField={updateField} />
2735
- <CheckBox value={config.legend.verticalSorted} section='legend' fieldName='verticalSorted' label='Vertical sorted Legend' updateField={updateField} />
2736
- </>
2737
- )}
2738
- <TextField type='textarea' value={config.legend.description} updateField={updateField} section='legend' fieldName='description' label='Legend Description' />
2739
- </AccordionItemPanel>
2740
- </AccordionItem>
2741
- )}
2742
- {visSupportsFilters() && (
2743
- <AccordionItem>
2744
- <AccordionItemHeading>
2745
- <AccordionItemButton>Filters</AccordionItemButton>
2746
- </AccordionItemHeading>
2747
- <AccordionItemPanel>
2748
- {config.filters && (
2749
- <>
2750
- {/* prettier-ignore */}
2751
- <Select
2752
- value={config.filterBehavior}
2753
- fieldName='filterBehavior'
2754
- label='Filter Behavior'
2001
+ {config.orientation === 'horizontal' ? (
2002
+ <>
2003
+ {visSupportsDateCategoryAxisLine() && <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2004
+ {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
2005
+ </>
2006
+ ) : (
2007
+ <>
2008
+ {visSupportsDateCategoryAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2009
+ {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
2010
+ {visSupportsDateCategoryAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
2011
+ </>
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'
2755
2028
  updateField={updateField}
2756
- options={['Apply Button', 'Filter Change']}
2029
+ />
2030
+ <CheckBox
2757
2031
  tooltip={
2758
2032
  <Tooltip style={{ textTransform: 'none' }}>
2759
2033
  <Tooltip.Target>
2760
2034
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2761
2035
  </Tooltip.Target>
2762
2036
  <Tooltip.Content>
2763
- <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>
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>
2764
2038
  </Tooltip.Content>
2765
2039
  </Tooltip>
2766
2040
  }
2767
- />
2768
- <br />
2769
- </>
2770
- )}
2771
- {config.filters && (
2772
- <ul className='filters-list'>
2773
- {/* Whether filters should apply onChange or Apply Button */}
2774
-
2775
- {config.filters.map((filter, index) => {
2776
- if (filter.type === 'url') return <></>
2777
-
2778
- return (
2779
- <fieldset className='edit-block' key={index}>
2780
- <button
2781
- type='button'
2782
- className='remove-column'
2783
- onClick={() => {
2784
- removeFilter(index)
2785
- }}
2786
- >
2787
- Remove
2788
- </button>
2041
+ value={config.xAxis.showSuppressedSymbol}
2042
+ section='xAxis'
2043
+ fieldName='showSuppressedSymbol'
2044
+ label='Display suppressed data symbol'
2045
+ updateField={updateField}
2046
+ />
2047
+
2048
+ {config.series?.length === 1 && config.visualizationType === 'Bar' && (
2049
+ <>
2050
+ {/* HIGHLIGHTED BARS */}
2051
+ <label htmlFor='barHighlight'>Bar Highlighting</label>
2052
+ {config.series.length === 1 &&
2053
+ highlightedBarValues.map((highlightedBarValue, i) => (
2054
+ <fieldset>
2055
+ <div className='edit-block' key={`highlighted-bar-${i}`}>
2056
+ <button className='remove-column' onClick={e => handleRemoveHighlightedBar(e, i)}>
2057
+ Remove
2058
+ </button>
2059
+ <p>Highlighted Bar {i + 1}</p>
2060
+ <label>
2061
+ <span className='edit-label column-heading'>Value</span>
2062
+ <select value={config.highlightedBarValues[i].value} onChange={e => handleUpdateHighlightedBar(e, i)}>
2063
+ <option value=''>- Select Value -</option>
2064
+ {highlightedSeriesValues && [...new Set(highlightedSeriesValues)].sort().map(option => <option key={`special-class-value-option-${i}-${option}`}>{option}</option>)}
2065
+ </select>
2066
+ </label>
2067
+ <label>
2068
+ <span className='edit-label column-heading'>Color</span>
2069
+ <input type='text' value={config.highlightedBarValues[i].color ? config.highlightedBarValues[i].color : ''} onChange={e => handleUpdateHighlightedBarColor(e, i)} />
2070
+ </label>
2071
+ <label>
2072
+ <span className='edit-label column-heading'>Border Width</span>
2073
+ <input max='5' min='0' type='number' value={config.highlightedBarValues[i].borderWidth ? config.highlightedBarValues[i].borderWidth : ''} onChange={e => handleUpdateHighlightedBorderWidth(e, i)} />
2074
+ </label>
2075
+ <label>
2076
+ <span className='edit-label column-heading'>Legend Label</span>
2077
+ <input type='text' value={config.highlightedBarValues[i].legendLabel ? config.highlightedBarValues[i].legendLabel : ''} onChange={e => handleHighlightedBarLegendLabel(e, i)} />
2078
+ </label>
2079
+ </div>
2080
+ </fieldset>
2081
+ ))}
2082
+ <button className='btn full-width' onClick={e => handleAddNewHighlightedBar(e)}>
2083
+ Add Highlighted Bar
2084
+ </button>
2085
+ </>
2086
+ )}
2087
+ </>
2088
+ )}
2089
+
2090
+ {config.visualizationType === 'Pie' && (
2091
+ <>
2092
+ <CheckBox
2093
+ value={config.exclusions.active}
2094
+ section='exclusions'
2095
+ fieldName='active'
2096
+ label={'Exclude one or more values'}
2097
+ updateField={updateField}
2098
+ tooltip={
2099
+ <Tooltip style={{ textTransform: 'none' }}>
2100
+ <Tooltip.Target>
2101
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2102
+ </Tooltip.Target>
2103
+ <Tooltip.Content>
2104
+ <p>When this option is checked, you can select values for exclusion from the pie segments.</p>
2105
+ </Tooltip.Content>
2106
+ </Tooltip>
2107
+ }
2108
+ />
2109
+ {config.exclusions.active && (
2110
+ <>
2111
+ {config.exclusions.keys.length > 0 && (
2112
+ <>
2113
+ <fieldset>
2114
+ <legend className='edit-label'>Excluded Keys</legend>
2115
+ </fieldset>
2116
+ <ExclusionsList />
2117
+ </>
2118
+ )}
2119
+
2120
+ <Select
2121
+ fieldName='visualizationType'
2122
+ label='Add Exclusion'
2123
+ initial='Select'
2124
+ onChange={e => {
2125
+ if (e.target.value !== '' && e.target.value !== 'Select') {
2126
+ addNewExclusion(e.target.value)
2127
+ }
2128
+ e.target.value = ''
2129
+ }}
2130
+ options={getDataValues(config.xAxis.dataKey, true)}
2131
+ />
2132
+ </>
2133
+ )}
2134
+ </>
2135
+ )}
2136
+
2137
+ {/* anchors */}
2138
+ {visHasAnchors() && config.orientation !== 'horizontal' && (
2139
+ <div className='edit-block'>
2140
+ <span className='edit-label column-heading'>Anchors</span>
2141
+ <Accordion allowZeroExpanded>
2142
+ {config.xAxis?.anchors?.map((anchor, index) => (
2143
+ <AccordionItem className='series-item series-item--chart' key={`xaxis-anchors-2-${index}`}>
2144
+ <AccordionItemHeading className='series-item__title'>
2145
+ <>
2146
+ <AccordionItemButton className={'accordion__button accordion__button'}>
2147
+ Anchor {index + 1}
2148
+ <button
2149
+ className='series-list__remove'
2150
+ onClick={e => {
2151
+ e.preventDefault()
2152
+ const copiedAnchorGroups = [...config.xAxis.anchors]
2153
+ copiedAnchorGroups.splice(index, 1)
2154
+ updateConfig({
2155
+ ...config,
2156
+ xAxis: {
2157
+ ...config.xAxis,
2158
+ anchors: copiedAnchorGroups
2159
+ }
2160
+ })
2161
+ }}
2162
+ >
2163
+ Remove
2164
+ </button>
2165
+ </AccordionItemButton>
2166
+ </>
2167
+ </AccordionItemHeading>
2168
+ <AccordionItemPanel>
2789
2169
  <label>
2790
- <span className='edit-label column-heading'>Filter</span>
2791
- <select
2792
- value={filter.columnName}
2170
+ <span>Anchor Value</span>
2171
+ <Tooltip style={{ textTransform: 'none' }}>
2172
+ <Tooltip.Target>
2173
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2174
+ </Tooltip.Target>
2175
+ <Tooltip.Content>
2176
+ <p>Enter the value as its shown in the data column</p>
2177
+ </Tooltip.Content>
2178
+ </Tooltip>
2179
+ <input
2180
+ type='text'
2181
+ value={config.xAxis.anchors[index].value ? config.xAxis.anchors[index].value : ''}
2793
2182
  onChange={e => {
2794
- updateFilterProp('columnName', index, e.target.value)
2183
+ e.preventDefault()
2184
+ const copiedAnchors = [...config.xAxis.anchors]
2185
+ copiedAnchors[index].value = e.target.value
2186
+ updateConfig({
2187
+ ...config,
2188
+ xAxis: {
2189
+ ...config.xAxis,
2190
+ anchors: copiedAnchors
2191
+ }
2192
+ })
2795
2193
  }}
2796
- >
2797
- <option value=''>- Select Option -</option>
2798
- {getFilters().map((dataKey, index) => (
2799
- <option value={dataKey} key={index}>
2800
- {dataKey}
2801
- </option>
2802
- ))}
2803
- </select>
2194
+ />
2804
2195
  </label>
2805
2196
 
2806
2197
  <label>
2807
- <span className='edit-showDropdown column-heading'>Show Filter Input</span>
2198
+ <span>Anchor Color</span>
2808
2199
  <input
2809
- type='checkbox'
2810
- checked={filter.showDropdown === undefined ? true : filter.showDropdown}
2200
+ type='text'
2201
+ value={config.xAxis.anchors[index].color ? config.xAxis.anchors[index].color : ''}
2811
2202
  onChange={e => {
2812
- updateFilterProp('showDropdown', index, e.target.checked)
2203
+ e.preventDefault()
2204
+ const copiedAnchors = [...config.xAxis.anchors]
2205
+ copiedAnchors[index].color = e.target.value
2206
+ updateConfig({
2207
+ ...config,
2208
+ xAxis: {
2209
+ ...config.xAxis,
2210
+ anchors: copiedAnchors
2211
+ }
2212
+ })
2813
2213
  }}
2814
2214
  />
2815
2215
  </label>
2816
2216
 
2817
2217
  <label>
2818
- <span className='edit-label column-heading'>Filter Style</span>
2819
-
2218
+ Anchor Line Style
2820
2219
  <select
2821
- value={filter.filterStyle}
2220
+ value={config.xAxis.anchors[index].lineStyle || ''}
2822
2221
  onChange={e => {
2823
- updateFilterProp('filterStyle', index, e.target.value)
2222
+ const copiedAnchors = [...config.xAxis.anchors]
2223
+ copiedAnchors[index].lineStyle = e.target.value
2224
+ updateConfig({
2225
+ ...config,
2226
+ xAxis: {
2227
+ ...config.xAxis,
2228
+ anchors: copiedAnchors
2229
+ }
2230
+ })
2824
2231
  }}
2825
2232
  >
2826
- {filterStyleOptions.map((item, index) => {
2827
- return (
2828
- <option key={`filter-style-${index}`} value={item}>
2829
- {item}
2830
- </option>
2831
- )
2832
- })}
2233
+ <option>Select</option>
2234
+ {lineOptions.map(line => (
2235
+ <option key={line.key}>{line.value}</option>
2236
+ ))}
2833
2237
  </select>
2834
2238
  </label>
2239
+ </AccordionItemPanel>
2240
+ </AccordionItem>
2241
+ ))}
2242
+ </Accordion>
2243
+
2244
+ <button
2245
+ className='btn full-width'
2246
+ onClick={e => {
2247
+ e.preventDefault()
2248
+ const anchors = [...config.xAxis.anchors]
2249
+ anchors.push({} as Anchor)
2250
+ updateConfig({
2251
+ ...config,
2252
+ xAxis: {
2253
+ ...config.xAxis,
2254
+ anchors
2255
+ }
2256
+ })
2257
+ }}
2258
+ >
2259
+ Add Anchor
2260
+ </button>
2261
+ </div>
2262
+ )}
2263
+
2264
+ {visHasAnchors() && config.orientation === 'horizontal' && (
2265
+ <div className='edit-block'>
2266
+ <span className='edit-label column-heading'>Anchors</span>
2267
+ <Accordion allowZeroExpanded>
2268
+ {config.yAxis?.anchors?.map((anchor, index) => (
2269
+ <AccordionItem className='series-item series-item--chart' key={`accordion-yaxis-anchors-${index}`}>
2270
+ <AccordionItemHeading className='series-item__title'>
2271
+ <>
2272
+ <AccordionItemButton className={'accordion__button accordion__button'}>
2273
+ Anchor {index + 1}
2274
+ <button
2275
+ className='series-list__remove'
2276
+ onClick={e => {
2277
+ e.preventDefault()
2278
+ const copiedAnchorGroups = [...config.yAxis.anchors]
2279
+ copiedAnchorGroups.splice(index, 1)
2280
+ updateConfig({
2281
+ ...config,
2282
+ yAxis: {
2283
+ ...config.yAxis,
2284
+ anchors: copiedAnchorGroups
2285
+ }
2286
+ })
2287
+ }}
2288
+ >
2289
+ Remove
2290
+ </button>
2291
+ </AccordionItemButton>
2292
+ </>
2293
+ </AccordionItemHeading>
2294
+ <AccordionItemPanel>
2835
2295
  <label>
2836
- <span className='edit-label column-heading'>Label</span>
2296
+ <span>Anchor Value</span>
2297
+ <Tooltip style={{ textTransform: 'none' }}>
2298
+ <Tooltip.Target>
2299
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2300
+ </Tooltip.Target>
2301
+ <Tooltip.Content>
2302
+ <p>Enter the value as its shown in the data column</p>
2303
+ </Tooltip.Content>
2304
+ </Tooltip>
2837
2305
  <input
2838
2306
  type='text'
2839
- value={filter.label}
2307
+ value={config.yAxis.anchors[index].value ? config.yAxis.anchors[index].value : ''}
2840
2308
  onChange={e => {
2841
- updateFilterProp('label', index, e.target.value)
2309
+ e.preventDefault()
2310
+ const copiedAnchors = [...config.yAxis.anchors]
2311
+ copiedAnchors[index].value = e.target.value
2312
+ updateConfig({
2313
+ ...config,
2314
+ yAxis: {
2315
+ ...config.yAxis,
2316
+ anchors: copiedAnchors
2317
+ }
2318
+ })
2842
2319
  }}
2843
2320
  />
2844
2321
  </label>
2845
2322
 
2846
2323
  <label>
2847
- <span className='edit-label column-heading'>Default Value Set By Query String Parameter</span>
2324
+ <span>Anchor Color</span>
2848
2325
  <input
2849
2326
  type='text'
2850
- value={filter.setByQueryParameter}
2327
+ value={config.yAxis.anchors[index].color ? config.yAxis.anchors[index].color : ''}
2851
2328
  onChange={e => {
2852
- updateFilterProp('setByQueryParameter', index, e.target.value)
2329
+ e.preventDefault()
2330
+ const copiedAnchors = [...config.yAxis.anchors]
2331
+ copiedAnchors[index].color = e.target.value
2332
+ updateConfig({
2333
+ ...config,
2334
+ yAxis: {
2335
+ ...config.yAxis,
2336
+ anchors: copiedAnchors
2337
+ }
2338
+ })
2853
2339
  }}
2854
2340
  />
2855
2341
  </label>
2856
2342
 
2857
2343
  <label>
2858
- <span className='edit-filterOrder column-heading'>Filter Order</span>
2859
- <select value={filter.order ? filter.order : 'asc'} onChange={e => updateFilterProp('order', index, e.target.value)}>
2860
- {filterOrderOptions.map((option, index) => {
2861
- return (
2862
- <option value={option.value} key={`filter-${index}`}>
2863
- {option.label}
2864
- </option>
2865
- )
2866
- })}
2344
+ Anchor Line Style
2345
+ <select
2346
+ value={config.yAxis.anchors[index].lineStyle || ''}
2347
+ onChange={e => {
2348
+ const copiedAnchors = [...config.yAxis.anchors]
2349
+ copiedAnchors[index].lineStyle = e.target.value
2350
+ updateConfig({
2351
+ ...config,
2352
+ yAxis: {
2353
+ ...config.yAxis,
2354
+ anchors: copiedAnchors
2355
+ }
2356
+ })
2357
+ }}
2358
+ >
2359
+ <option>Select</option>
2360
+ {lineOptions.map(line => (
2361
+ <option key={line.key}>{line.value}</option>
2362
+ ))}
2867
2363
  </select>
2868
-
2869
- {filter.order === 'cust' && (
2870
- <DragDropContext onDragEnd={({ source, destination }) => handleFilterOrder(source.index, destination.index, index, config.filters[index])}>
2871
- <Droppable droppableId='filter_order'>
2872
- {provided => (
2873
- <ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
2874
- {config.filters[index]?.values.map((value, index) => {
2875
- return (
2876
- <Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
2877
- {(provided, snapshot) => (
2878
- <li>
2879
- <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
2880
- {value}
2881
- </div>
2882
- </li>
2883
- )}
2884
- </Draggable>
2885
- )
2886
- })}
2887
- {provided.placeholder}
2888
- </ul>
2889
- )}
2890
- </Droppable>
2891
- </DragDropContext>
2892
- )}
2893
2364
  </label>
2894
- </fieldset>
2895
- )
2896
- })}
2897
- </ul>
2365
+ </AccordionItemPanel>
2366
+ </AccordionItem>
2367
+ ))}
2368
+ </Accordion>
2369
+
2370
+ <button
2371
+ className='btn full-width'
2372
+ onClick={e => {
2373
+ e.preventDefault()
2374
+ const anchors = [...config.yAxis.anchors]
2375
+ anchors.push({} as Anchor)
2376
+ updateConfig({
2377
+ ...config,
2378
+ yAxis: {
2379
+ ...config.yAxis,
2380
+ anchors
2381
+ }
2382
+ })
2383
+ }}
2384
+ >
2385
+ Add Anchor
2386
+ </button>
2387
+ </div>
2388
+ )}
2389
+ </AccordionItemPanel>
2390
+ </AccordionItem>
2391
+ )}
2392
+ <Panels.Regions name='Regions' />
2393
+
2394
+ {/* Columns */}
2395
+ {config.visualizationType !== 'Box Plot' && (
2396
+ <AccordionItem>
2397
+ <AccordionItemHeading>
2398
+ <AccordionItemButton>Columns</AccordionItemButton>
2399
+ </AccordionItemHeading>
2400
+ <AccordionItemPanel>
2401
+ <ColumnsEditor config={config} updateField={updateField} deleteColumn={removeAdditionalColumn} />{' '}
2402
+ </AccordionItemPanel>
2403
+ </AccordionItem>
2404
+ )}
2405
+ {/* End Columns */}
2406
+ {visHasLegend() && (
2407
+ <AccordionItem>
2408
+ <AccordionItemHeading>
2409
+ <AccordionItemButton>Legend</AccordionItemButton>
2410
+ </AccordionItemHeading>
2411
+ <AccordionItemPanel>
2412
+ <CheckBox value={config.legend.reverseLabelOrder} section='legend' fieldName='reverseLabelOrder' label='Reverse Labels' updateField={updateField} />
2413
+ {/* <fieldset className="checkbox-group">
2414
+ <CheckBox value={config.legend.dynamicLegend} section="legend" fieldName="dynamicLegend" label="Dynamic Legend" updateField={updateField}/>
2415
+ {config.legend.dynamicLegend && (
2416
+ <>
2417
+ <TextField value={config.legend.dynamicLegendDefaultText} section="legend" fieldName="dynamicLegendDefaultText" label="Dynamic Legend Default Text" updateField={updateField} />
2418
+ <TextField value={config.legend.dynamicLegendItemLimit} type="number" min="0" section="legend" fieldName="dynamicLegendItemLimit" label={'Dynamic Legend Limit'} className="number-narrow" updateField={updateField}/>
2419
+ <TextField value={config.legend.dynamicLegendItemLimitMessage} section="legend" fieldName="dynamicLegendItemLimitMessage" label="Dynamic Legend Item Limit Message" updateField={updateField} />
2420
+ <TextField value={config.legend.dynamicLegendChartMessage} section="legend" fieldName="dynamicLegendChartMessage" label="Dynamic Legend Chart Message" updateField={updateField} />
2421
+ </>
2898
2422
  )}
2899
- {!config.filters && <p style={{ textAlign: 'center' }}>There are currently no filters.</p>}
2900
- <button type='button' onClick={addNewFilter} className='btn full-width'>
2901
- Add Filter
2902
- </button>
2903
- </AccordionItemPanel>
2904
- </AccordionItem>
2905
- )}
2906
- <Panels.Visual name='Visual' />
2907
- {/* Spark Line has no data table */}
2908
- {config.visualizationType !== 'Spark Line' && (
2909
- <AccordionItem>
2910
- <AccordionItemHeading>
2911
- <AccordionItemButton>Data Table</AccordionItemButton>
2912
- </AccordionItemHeading>
2913
- <AccordionItemPanel>
2914
- <DataTableEditor config={config} columns={Object.keys(data[0] || {})} updateField={updateField} isDashboard={isDashboard} isLoadedFromUrl={isLoadedFromUrl} />{' '}
2915
- </AccordionItemPanel>
2916
- </AccordionItem>
2917
- )}
2918
- {/* {(config.visualizationType === 'Bar' || config.visualizationType === 'Line') && <Panels.DateHighlighting name='Date Highlighting' />} */}
2919
- </Accordion>
2920
- {config.type !== 'Spark Line' && <AdvancedEditor loadConfig={updateConfig} state={config} convertStateToConfig={convertStateToConfig} />}
2921
- </section>
2922
- </section>
2423
+ </fieldset> */}
2424
+ <CheckBox
2425
+ value={config.legend.hide ? true : false}
2426
+ section='legend'
2427
+ fieldName='hide'
2428
+ label='Hide Legend'
2429
+ updateField={updateField}
2430
+ tooltip={
2431
+ <Tooltip style={{ textTransform: 'none' }}>
2432
+ <Tooltip.Target>
2433
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2434
+ </Tooltip.Target>
2435
+ <Tooltip.Content>
2436
+ <p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
2437
+ </Tooltip.Content>
2438
+ </Tooltip>
2439
+ }
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
+ />
2458
+ {/* {config.visualizationType === 'Box Plot' &&
2459
+ <>
2460
+ <CheckBox value={config.boxplot.legend.displayHowToReadText} fieldName='displayHowToReadText' section='boxplot' subsection='legend' label='Display How To Read Text' updateField={updateField} />
2461
+ <TextField type='textarea' value={config.boxplot.legend.howToReadText} updateField={updateField} fieldName='howToReadText' section='boxplot' subsection='legend' label='How to read text' />
2462
+ </>
2463
+ } */}
2464
+ {config.visualizationType === 'Line' && <CheckBox value={config.legend.lineMode} section='legend' fieldName='lineMode' label='Show Lined Style Legend' updateField={updateField} />}
2465
+ {config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1 && (
2466
+ <Select value={config.legend.colorCode} section='legend' fieldName='colorCode' label='Color code by category' initial='Select' updateField={updateField} options={getDataValueOptions(data)} />
2467
+ )}
2468
+ <Select value={config.legend.behavior} section='legend' fieldName='behavior' label='Legend Behavior (When clicked)' updateField={(...[section, , fieldName, value]) => updateBehavior(section, fieldName, value)} options={['highlight', 'isolate']} />
2469
+ {visHasLegendAxisAlign() && <CheckBox value={config.legend.axisAlign} fieldName='axisAlign' section='legend' label='Align to Axis on Isolate' updateField={updateField} />}
2470
+
2471
+ {config.legend.behavior === 'highlight' && config.tooltips.singleSeries && <CheckBox value={config.legend.highlightOnHover} section='legend' fieldName='highlightOnHover' label='HIGHLIGHT DATA SERIES ON HOVER' updateField={updateField} />}
2472
+
2473
+ {/* start: isolated values */}
2474
+ {visHasSelectableLegendValues && config.legend.behavior === 'isolate' && !colorCodeByCategory && (
2475
+ <fieldset className='primary-fieldset edit-block' key={'additional-highlight-values'}>
2476
+ <label>
2477
+ <span className='edit-label'>
2478
+ Isolate Data Series
2479
+ <Tooltip style={{ textTransform: 'none' }}>
2480
+ <Tooltip.Target>
2481
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2482
+ </Tooltip.Target>
2483
+ <Tooltip.Content>
2484
+ <p>You can choose data series that are shown on load. Others will be added when the user clicks on them in the legend.</p>
2485
+ </Tooltip.Content>
2486
+ </Tooltip>
2487
+ </span>
2488
+ </label>
2489
+ {config.legend.seriesHighlight &&
2490
+ config.legend.seriesHighlight.map((val, i) => (
2491
+ <fieldset className='edit-block' key={`${val}-${i}`}>
2492
+ <button
2493
+ className='remove-column'
2494
+ onClick={event => {
2495
+ event.preventDefault()
2496
+ const updatedSeriesHighlight = [...config.legend.seriesHighlight]
2497
+ updatedSeriesHighlight.splice(i, 1)
2498
+ updateField('legend', null, 'seriesHighlight', updatedSeriesHighlight)
2499
+ if (!updatedSeriesHighlight.length) {
2500
+ highlightReset()
2501
+ }
2502
+ }}
2503
+ >
2504
+ Remove
2505
+ </button>
2506
+ <Select
2507
+ value={config.legend.seriesHighlight[i]}
2508
+ fieldName='seriesHighlight'
2509
+ label='Isolate Value'
2510
+ onChange={e => {
2511
+ const updatedSeriesHighlight = [...config.legend.seriesHighlight]
2512
+ if (!updatedSeriesHighlight.includes(e.target.value)) {
2513
+ updatedSeriesHighlight[i] = e.target.value
2514
+ updateSeriesIsolateValues([...updatedSeriesHighlight])
2515
+ }
2516
+ }}
2517
+ options={getLegendColumns()}
2518
+ />
2519
+ </fieldset>
2520
+ ))}
2521
+ <button
2522
+ className={'btn full-width'}
2523
+ onClick={event => {
2524
+ event.preventDefault()
2525
+ const legendColumns = getLegendColumns()
2526
+ const updatedSeriesHighlight = [...config.legend.seriesHighlight]
2527
+ const seriesLength = updatedSeriesHighlight.length
2528
+ if (seriesLength < legendColumns.length) {
2529
+ const [newSeriesHighlight] = legendColumns.filter(d => !updatedSeriesHighlight.includes(d))
2530
+ updatedSeriesHighlight.push(newSeriesHighlight)
2531
+ updateSeriesIsolateValues([...updatedSeriesHighlight])
2532
+ }
2533
+ }}
2534
+ >
2535
+ Add Isolate Value
2536
+ </button>
2537
+ </fieldset>
2538
+ )}
2539
+ {/* end: isolated values */}
2540
+
2541
+ <TextField value={config.legend.label} section='legend' fieldName='label' label='Title' updateField={updateField} />
2542
+ <Select value={config.legend.position} section='legend' fieldName='position' label='Position' updateField={updateField} options={['right', 'left', 'bottom']} />
2543
+ {config.legend.position === 'bottom' && (
2544
+ <>
2545
+ <CheckBox value={config.legend.singleRow} section='legend' fieldName='singleRow' label='Single Row Legend' updateField={updateField} />
2546
+ <CheckBox value={config.legend.verticalSorted} section='legend' fieldName='verticalSorted' label='Vertical sorted Legend' updateField={updateField} />
2547
+ </>
2548
+ )}
2549
+ <TextField type='textarea' value={config.legend.description} updateField={updateField} section='legend' fieldName='description' label='Legend Description' />
2550
+ </AccordionItemPanel>
2551
+ </AccordionItem>
2552
+ )}
2553
+ {visSupportsFilters() && (
2554
+ <AccordionItem>
2555
+ <AccordionItemHeading>
2556
+ <AccordionItemButton>Filters</AccordionItemButton>
2557
+ </AccordionItemHeading>
2558
+ <AccordionItemPanel>
2559
+ <VizFilterEditor config={config} updateField={updateField} rawData={rawData} />
2560
+ </AccordionItemPanel>
2561
+ </AccordionItem>
2562
+ )}
2563
+ <Panels.Visual name='Visual' />
2564
+ {/* Spark Line has no data table */}
2565
+ {config.visualizationType !== 'Spark Line' && (
2566
+ <AccordionItem>
2567
+ <AccordionItemHeading>
2568
+ <AccordionItemButton>Data Table</AccordionItemButton>
2569
+ </AccordionItemHeading>
2570
+ <AccordionItemPanel>
2571
+ <DataTableEditor config={config} columns={Object.keys(data[0] || {})} updateField={updateField} isDashboard={isDashboard} isLoadedFromUrl={isLoadedFromUrl} />{' '}
2572
+ </AccordionItemPanel>
2573
+ </AccordionItem>
2574
+ )}
2575
+ {/* {(config.visualizationType === 'Bar' || config.visualizationType === 'Line') && <Panels.DateHighlighting name='Date Highlighting' />} */}
2576
+ </Accordion>
2577
+ {config.type !== 'Spark Line' && <AdvancedEditor loadConfig={updateConfig} state={config} convertStateToConfig={convertStateToConfig} />}
2578
+ </Layout.Sidebar>
2923
2579
  </ErrorBoundary>
2924
2580
  </EditorPanelContext.Provider>
2925
2581
  )