@cdc/chart 4.23.10 → 4.24.1

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 (125) hide show
  1. package/dist/cdcchart.js +34606 -32218
  2. package/examples/feature/bar/additional-column-tooltip.json +446 -0
  3. package/examples/feature/bar/example-bar-chart.json +1 -46
  4. package/examples/feature/bar/lollipop.json +156 -0
  5. package/examples/feature/bar/tall-data.json +98 -0
  6. package/examples/feature/combo/planet-combo-example-config.json +99 -9
  7. package/examples/feature/dev-4261.json +399 -0
  8. package/examples/feature/forest-plot/forest-plot.json +63 -19
  9. package/examples/feature/forest-plot/{broken.json → linear.json} +77 -23
  10. package/examples/feature/forest-plot/log.json +26 -0
  11. package/examples/feature/forest-plot/logarithmic.json +271 -0
  12. package/examples/feature/line/line-chart-preliminary.json +346 -0
  13. package/examples/feature/line/line-points.json +340 -0
  14. package/examples/feature/regions/index.json +462 -0
  15. package/examples/feature/scatterplot/scatterplot.json +272 -33
  16. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +181 -48
  17. package/examples/private/chart-t.json +3740 -0
  18. package/examples/private/combo.json +369 -0
  19. package/examples/private/epi-data.csv +13 -0
  20. package/examples/private/epi-data.json +62 -0
  21. package/examples/private/epi.json +403 -0
  22. package/examples/private/occupancy.json +109283 -0
  23. package/examples/private/prod-line-config.json +401 -0
  24. package/examples/private/region-data.json +822 -0
  25. package/examples/private/region-testing.json +312 -0
  26. package/examples/private/scaling.json +45325 -0
  27. package/examples/private/testing-data.json +1739 -0
  28. package/examples/private/testing.json +816 -0
  29. package/examples/sparkline-multilple.json +846 -0
  30. package/index.html +12 -8
  31. package/package.json +3 -3
  32. package/src/CdcChart.tsx +42 -211
  33. package/src/ConfigContext.tsx +6 -0
  34. package/src/_stories/Chart.stories.tsx +188 -0
  35. package/src/_stories/Chart.tooltip.stories.tsx +305 -0
  36. package/src/_stories/ChartBrush.stories.tsx +19 -0
  37. package/src/_stories/ChartEditor.stories.tsx +22 -0
  38. package/src/_stories/ChartLine.preliminary.tsx +19 -0
  39. package/src/_stories/ChartSuppress.stories.tsx +19 -0
  40. package/src/_stories/_mock/brush_mock.json +393 -0
  41. package/src/_stories/_mock/pie_config.json +191 -0
  42. package/src/_stories/_mock/pie_data.json +218 -0
  43. package/src/_stories/_mock/preliminary_mock.json +346 -0
  44. package/src/_stories/_mock/suppress_mock.json +911 -0
  45. package/src/components/{AreaChart.Stacked.jsx → AreaChart/components/AreaChart.Stacked.jsx} +6 -7
  46. package/src/components/{AreaChart.jsx → AreaChart/components/AreaChart.jsx} +7 -36
  47. package/src/components/AreaChart/index.tsx +4 -0
  48. package/src/components/{BarChart.Horizontal.jsx → BarChart/components/BarChart.Horizontal.tsx} +111 -34
  49. package/src/components/{BarChart.StackedHorizontal.jsx → BarChart/components/BarChart.StackedHorizontal.tsx} +55 -20
  50. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +106 -0
  51. package/src/components/{BarChart.Vertical.jsx → BarChart/components/BarChart.Vertical.tsx} +162 -34
  52. package/src/components/BarChart/components/BarChart.jsx +39 -0
  53. package/src/components/{BarChartType.jsx → BarChart/components/BarChartType.jsx} +0 -2
  54. package/src/components/BarChart/components/context.tsx +13 -0
  55. package/src/components/BarChart/index.tsx +3 -0
  56. package/src/components/{BoxPlot.jsx → BoxPlot/BoxPlot.jsx} +1 -1
  57. package/src/components/BoxPlot/index.tsx +3 -0
  58. package/src/components/DeviationBar.jsx +4 -3
  59. package/src/components/{EditorPanel.jsx → EditorPanel/EditorPanel.tsx} +807 -865
  60. package/src/components/EditorPanel/components/Panel.DateHighlighting.tsx +109 -0
  61. package/src/components/{ForestPlotSettings.jsx → EditorPanel/components/Panel.ForestPlotSettings.tsx} +190 -220
  62. package/src/components/EditorPanel/components/Panel.Regions.tsx +168 -0
  63. package/src/components/{Series.jsx → EditorPanel/components/Panel.Series.tsx} +23 -4
  64. package/src/components/EditorPanel/components/PanelProps.ts +3 -0
  65. package/src/components/EditorPanel/components/Panels.tsx +13 -0
  66. package/src/components/EditorPanel/components/panels.scss +72 -0
  67. package/src/components/EditorPanel/editor-panel.scss +751 -0
  68. package/src/components/EditorPanel/index.tsx +3 -0
  69. package/src/{hooks → components/EditorPanel}/useEditorPermissions.js +50 -5
  70. package/src/components/{Forecasting.jsx → Forecasting/Forecasting.jsx} +1 -1
  71. package/src/components/Forecasting/index.tsx +3 -0
  72. package/src/components/ForestPlot/ForestPlot.tsx +254 -0
  73. package/src/components/ForestPlot/ForestPlotProps.ts +18 -0
  74. package/src/components/ForestPlot/index.scss +1 -0
  75. package/src/components/ForestPlot/index.tsx +3 -0
  76. package/src/components/Legend/Legend.tsx +347 -0
  77. package/src/components/Legend/index.tsx +3 -0
  78. package/src/components/LineChart/LineChartProps.ts +46 -0
  79. package/src/components/{LineChart.Circle.tsx → LineChart/components/LineChart.Circle.tsx} +36 -30
  80. package/src/components/LineChart/helpers.ts +45 -0
  81. package/src/components/LineChart/index.scss +1 -0
  82. package/src/components/{LineChart.tsx → LineChart/index.tsx} +83 -42
  83. package/src/components/LinearChart.jsx +125 -82
  84. package/src/components/PairedBarChart.jsx +2 -2
  85. package/src/components/{PieChart.jsx → PieChart/PieChart.tsx} +16 -7
  86. package/src/components/PieChart/index.tsx +3 -0
  87. package/src/components/Regions/components/Regions.tsx +135 -0
  88. package/src/components/Regions/index.tsx +3 -0
  89. package/src/components/{ScatterPlot.jsx → ScatterPlot/ScatterPlot.jsx} +3 -3
  90. package/src/components/ScatterPlot/index.tsx +3 -0
  91. package/src/components/{SparkLine.jsx → Sparkline/SparkLine.jsx} +2 -2
  92. package/src/components/Sparkline/index.tsx +3 -0
  93. package/src/components/ZoomBrush.tsx +168 -0
  94. package/src/data/initial-state.js +30 -16
  95. package/src/helpers/abbreviateNumber.ts +17 -0
  96. package/src/helpers/computeMarginBottom.ts +55 -0
  97. package/src/helpers/filterData.ts +18 -0
  98. package/src/helpers/generateColorsArray.ts +8 -0
  99. package/src/helpers/getQuartiles.ts +30 -0
  100. package/src/helpers/handleChartAriaLabels.ts +19 -0
  101. package/src/helpers/handleLineType.ts +18 -0
  102. package/src/helpers/lineOptions.ts +18 -0
  103. package/src/helpers/sort.ts +7 -0
  104. package/src/helpers/tests/computeMarginBottom.test.ts +20 -0
  105. package/src/hooks/useBarChart.js +72 -7
  106. package/src/hooks/useColorScale.ts +50 -0
  107. package/src/hooks/{useMinMax.js → useMinMax.ts} +75 -23
  108. package/src/hooks/{useRightAxis.js → useRightAxis.ts} +10 -2
  109. package/src/hooks/{useScales.js → useScales.ts} +64 -17
  110. package/src/hooks/{useTooltip.jsx → useTooltip.tsx} +84 -55
  111. package/src/scss/main.scss +70 -38
  112. package/src/types/ChartConfig.ts +178 -0
  113. package/src/types/ChartContext.ts +54 -0
  114. package/src/types/ForestPlot.ts +53 -0
  115. package/examples/feature/scatterplot/scatterplot-continuous.csv +0 -17
  116. package/src/ConfigContext.jsx +0 -5
  117. package/src/components/BarChart.StackedVertical.jsx +0 -95
  118. package/src/components/BarChart.jsx +0 -30
  119. package/src/components/ForestPlot.jsx +0 -191
  120. package/src/components/Legend.jsx +0 -277
  121. package/src/scss/LinearChart.scss +0 -0
  122. package/src/scss/editor-panel.scss +0 -745
  123. package/src/scss/legend.scss +0 -206
  124. package/src/scss/mixins.scss +0 -0
  125. package/src/scss/variables.scss +0 -1
@@ -1,10 +1,8 @@
1
- import React, { useState, useEffect, useCallback, memo, useContext } from 'react'
1
+ import { useState, useEffect, useCallback, memo, useContext } from 'react'
2
2
  import { DragDropContext, Droppable, Draggable } from '@hello-pangea/dnd'
3
3
 
4
4
  import { Accordion, AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
5
5
 
6
- import { useDebounce } from 'use-debounce'
7
-
8
6
  // @cdc/core
9
7
  import { approvedCurveTypes } from '@cdc/core/helpers/lineChartHelpers'
10
8
  import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
@@ -12,213 +10,205 @@ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
12
10
  import Icon from '@cdc/core/components/ui/Icon'
13
11
  import InputToggle from '@cdc/core/components/inputs/InputToggle'
14
12
  import Tooltip from '@cdc/core/components/ui/Tooltip'
13
+ import { Select, TextField, CheckBox } from '@cdc/core/components/EditorPanel/Inputs'
15
14
 
16
15
  // chart components
17
- import ForestPlotSettings from './ForestPlotSettings'
18
- import Series from './Series'
16
+ import Panels from './components/Panels'
17
+ import Series from './components/Panel.Series.jsx'
19
18
 
20
19
  // cdc additional
21
- import { useColorPalette } from '../hooks/useColorPalette'
22
- import { useEditorPermissions } from '../hooks/useEditorPermissions'
20
+ import { useColorPalette } from '../../hooks/useColorPalette'
21
+ import { useEditorPermissions } from './useEditorPermissions'
23
22
  import { useFilters } from '@cdc/core/components/Filters'
24
- import { useHighlightedBars } from '../hooks/useHighlightedBars'
25
- import ConfigContext from '../ConfigContext'
26
- import useReduceData from '../hooks/useReduceData'
27
- import useRightAxis from '../hooks/useRightAxis'
28
- import WarningImage from '../images/warning.svg'
29
-
30
- /* eslint-disable react-hooks/rules-of-hooks */
31
- const TextField = memo(({ label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = 'input', i = null, min = null, ...attributes }) => {
32
- const [value, setValue] = useState(stateValue)
33
-
34
- const [debouncedValue] = useDebounce(value, 500)
23
+ import { useHighlightedBars } from '../../hooks/useHighlightedBars'
24
+ import ConfigContext from '../../ConfigContext'
25
+ import useReduceData from '../../hooks/useReduceData'
26
+ import useRightAxis from '../../hooks/useRightAxis'
27
+ import WarningImage from '../../images/warning.svg'
28
+ import useMinMax from '../../hooks/useMinMax'
29
+
30
+ import { type ChartConfig } from '../../types/ChartConfig'
31
+ import { type ChartContext } from '../../types/ChartContext'
32
+
33
+ import './editor-panel.scss'
34
+ import { Anchor } from '@cdc/core/types/Axis'
35
+ import DataTableEditor from '@cdc/core/components/EditorPanel/DataTableEditor'
36
+
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
+ }
35
47
 
36
- useEffect(() => {
37
- if ('string' === typeof debouncedValue && stateValue !== debouncedValue) {
38
- updateField(section, subsection, fieldName, debouncedValue, i)
39
- }
40
- }, [debouncedValue]) // eslint-disable-line
48
+ const getIconOptions = () => {
49
+ return ['star']
50
+ }
41
51
 
42
- let name = subsection ? `${section}-${subsection}-${fieldName}` : `${section}-${subsection}-${fieldName}`
52
+ let removeColumn = i => {
53
+ let suppressedData = []
43
54
 
44
- const onChange = e => {
45
- if ('number' !== type || min === null) {
46
- setValue(e.target.value)
47
- } else {
48
- if (!e.target.value || min <= parseFloat(e.target.value)) {
49
- setValue(e.target.value)
50
- } else {
51
- setValue(min.toString())
52
- }
55
+ if (config.suppressedData) {
56
+ suppressedData = [...config.suppressedData]
53
57
  }
54
- }
55
58
 
56
- let formElement = <input type='text' name={name} onChange={onChange} {...attributes} value={value} />
57
-
58
- if ('textarea' === type) {
59
- formElement = <textarea name={name} onChange={onChange} {...attributes} value={value}></textarea>
60
- }
59
+ suppressedData.splice(i, 1)
61
60
 
62
- if ('number' === type) {
63
- formElement = <input type='number' name={name} onChange={onChange} {...attributes} value={value} />
61
+ updateConfig({ ...config, suppressedData })
64
62
  }
65
63
 
66
- if ('date' === type) {
67
- formElement = <input type='date' name={name} onChange={onChange} {...attributes} value={value} />
64
+ let addColumn = () => {
65
+ let suppressedData = config.suppressedData ? [...config.suppressedData] : []
66
+ suppressedData.push({ label: '', column: '', value: '', icon: '' })
67
+ updateConfig({ ...config, suppressedData })
68
68
  }
69
69
 
70
- return (
71
- <label>
72
- <span className='edit-label column-heading'>
73
- {label}
74
- {tooltip}
75
- </span>
76
- {formElement}
77
- </label>
78
- )
79
- })
70
+ let update = (fieldName, value, i) => {
71
+ let suppressedData = []
80
72
 
81
- const CheckBox = memo(({ label, value, fieldName, section = null, subsection = null, tooltip, updateField, ...attributes }) => (
82
- <label className='checkbox column-heading'>
83
- <input
84
- type='checkbox'
85
- name={fieldName}
86
- checked={value}
87
- onChange={e => {
88
- updateField(section, subsection, fieldName, !value)
89
- }}
90
- {...attributes}
91
- />
92
- <span className='edit-label'>
93
- {label}
94
- {tooltip}
95
- </span>
96
- </label>
97
- ))
98
-
99
- const Select = memo(({ label, value, options, fieldName, section = null, subsection = null, required = false, tooltip, updateField, initial: initialValue, ...attributes }) => {
100
- let optionsJsx = options.map((optionName, index) => (
101
- <option value={optionName} key={index}>
102
- {optionName}
103
- </option>
104
- ))
73
+ if (config.suppressedData) {
74
+ suppressedData = [...config.suppressedData]
75
+ }
105
76
 
106
- if (initialValue) {
107
- optionsJsx.unshift(
108
- <option value='' key='initial'>
109
- {initialValue}
110
- </option>
111
- )
77
+ suppressedData[i][fieldName] = value
78
+ updateConfig({ ...config, suppressedData })
112
79
  }
113
80
 
114
81
  return (
115
- <label>
116
- <span className='edit-label'>
117
- {label}
118
- {tooltip}
119
- </span>
120
- <select
121
- className={required && !value ? 'warning' : ''}
122
- name={fieldName}
123
- value={value}
124
- onChange={event => {
125
- updateField(section, subsection, fieldName, event.target.value)
126
- }}
127
- {...attributes}
128
- >
129
- {optionsJsx}
130
- </select>
131
- </label>
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
+ </>
132
109
  )
133
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]
120
+ }
134
121
 
135
- const Regions = memo(({ config, updateConfig }) => {
136
- let regionUpdate = (fieldName, value, i) => {
137
- let regions = []
138
-
139
- if (config.regions) {
140
- regions = [...config.regions]
122
+ const getTypeOptions = () => {
123
+ if (config.visualizationType === 'Line' || config.visualizationType === 'Combo') {
124
+ return ['effect']
125
+ } else {
126
+ return ['suppression']
141
127
  }
142
-
143
- regions[i][fieldName] = value
144
- updateConfig({ ...config, regions })
145
128
  }
146
129
 
147
- // only for Regions
148
- let updateField = (section, subsection, fieldName, value, i) => regionUpdate(fieldName, value, i)
130
+ const getStyleOptions = () => {
131
+ if (config.visualizationType === 'Line' || config.visualizationType === 'Combo') {
132
+ return ['Open Circles']
133
+ }
134
+ if (config.visualizationType === 'Bar') {
135
+ return ['star']
136
+ }
137
+ }
149
138
 
150
139
  let removeColumn = i => {
151
- let regions = []
140
+ let preliminaryData = []
152
141
 
153
- if (config.regions) {
154
- regions = [...config.regions]
142
+ if (config.preliminaryData) {
143
+ preliminaryData = [...config.preliminaryData]
155
144
  }
156
145
 
157
- regions.splice(i, 1)
146
+ preliminaryData.splice(i, 1)
158
147
 
159
- updateConfig({ ...config, regions })
148
+ updateConfig({ ...config, preliminaryData })
160
149
  }
161
150
 
162
151
  let addColumn = () => {
163
- let regions = []
152
+ let preliminaryData = config.preliminaryData ? [...config.preliminaryData] : []
153
+ preliminaryData.push({ type: '', label: '', column: '', value: '', style: '' })
154
+ updateConfig({ ...config, preliminaryData })
155
+ }
164
156
 
165
- if (config.regions) {
166
- regions = [...config.regions]
167
- }
157
+ let update = (fieldName, value, i) => {
158
+ let preliminaryData = []
168
159
 
169
- regions.push({})
160
+ if (config.preliminaryData) {
161
+ preliminaryData = [...config.preliminaryData]
162
+ }
170
163
 
171
- updateConfig({ ...config, regions })
164
+ preliminaryData[i][fieldName] = value
165
+ updateConfig({ ...config, preliminaryData })
172
166
  }
173
167
 
174
168
  return (
175
169
  <>
176
- {config.regions &&
177
- config.regions.map(({ label, color, from, to, background }, i) => (
178
- <div className='edit-block' key={`region-${i}`}>
179
- <button
180
- type='button'
181
- className='remove-column'
182
- onClick={event => {
183
- event.preventDefault()
184
- removeColumn(i)
185
- }}
186
- >
187
- Remove
188
- </button>
189
- <TextField value={label} label='Region Label' fieldName='label' i={i} updateField={updateField} />
190
- <div className='two-col-inputs'>
191
- <TextField value={color} label='Text Color' fieldName='color' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
192
- <TextField value={background} label='Background' fieldName='background' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
193
- </div>
194
- <div className='two-col-inputs'>
195
- <TextField value={from} label='From Value' fieldName='from' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
196
- <TextField value={to} label='To Value' fieldName='to' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
170
+ {config.preliminaryData &&
171
+ config.preliminaryData.map(({ seriesKey, type, label, column, value, style }, i) => {
172
+ return (
173
+ <div key={`preliminaryData-${i}`} className='edit-block'>
174
+ <button
175
+ type='button'
176
+ className='remove-column'
177
+ onClick={event => {
178
+ event.preventDefault()
179
+ removeColumn(i)
180
+ }}
181
+ >
182
+ Remove
183
+ </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?.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
+
190
+ <TextField value={label} fieldName='label' label='Label' placeholder='' updateField={(section, subsection, fieldName, value) => update(fieldName, value, i)} />
197
191
  </div>
198
- </div>
199
- ))}
200
- {!config.regions && <p style={{ textAlign: 'center' }}>There are currently no regions.</p>}
201
- <button
202
- type='button'
203
- className='btn full-width'
204
- onClick={e => {
205
- e.preventDefault()
206
- addColumn()
207
- }}
208
- >
209
- Add Region
192
+ )
193
+ })}
194
+
195
+ <button type='button' onClick={addColumn} className='btn full-width'>
196
+ {config.visualizationType === 'Line' ? 'Add Special Line' : config.visualizationType === 'Bar' ? ' Add Special Bar' : 'Add Special Line/Bar'}
210
197
  </button>
211
198
  </>
212
199
  )
213
200
  })
214
201
 
215
202
  const EditorPanel = () => {
216
- const { config, updateConfig, transformedData: data, loading, colorPalettes, twoColorPalette, unfilteredData, excludedData, isDashboard, setParentConfig, missingRequiredSections, isDebug, setFilteredData, lineOptions, rawData } = useContext(ConfigContext)
203
+ const { config, updateConfig, transformedData: data, loading, colorPalettes, twoColorPalette, unfilteredData, excludedData, isDashboard, setParentConfig, missingRequiredSections, isDebug, setFilteredData, lineOptions, rawData } = useContext<ChartContext>(ConfigContext)
217
204
 
218
205
  const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
219
206
 
220
207
  const { twoColorPalettes, sequential, nonSequential } = useColorPalette(config, updateConfig)
221
208
 
209
+ const properties = { data, config }
210
+ const { leftMax, rightMax } = useMinMax(properties)
211
+
222
212
  const {
223
213
  enabledChartTypes,
224
214
  headerColors,
@@ -233,6 +223,10 @@ const EditorPanel = () => {
233
223
  visHasDataCutoff,
234
224
  visCanAnimate,
235
225
  visHasLegend,
226
+ visHasBrushChart,
227
+ visSupportsDateCategoryAxis,
228
+ visSupportsValueAxisMin,
229
+ visSupportsValueAxisMax,
236
230
  visSupportsDateCategoryAxisLabel,
237
231
  visSupportsDateCategoryAxisLine,
238
232
  visSupportsDateCategoryAxisTicks,
@@ -254,7 +248,8 @@ const EditorPanel = () => {
254
248
  visSupportsTooltipOpacity,
255
249
  visSupportsRankByValue,
256
250
  visSupportsResponsiveTicks,
257
- visSupportsDateCategoryHeight
251
+ visSupportsDateCategoryHeight,
252
+ visHasDataSuppression
258
253
  } = useEditorPermissions()
259
254
 
260
255
  // argument acts as props
@@ -280,11 +275,6 @@ const EditorPanel = () => {
280
275
  ...config,
281
276
  series: newSeries
282
277
  })
283
-
284
- // disable brush if categorical - or - for now if not Area Chart
285
- if (config.xAxis.type === 'categorical' || config.visualizationType !== 'Area Chart') {
286
- config.showChartBrush = false
287
- }
288
278
  }, [config.visualizationType]) // eslint-disable-line
289
279
 
290
280
  // Scatter Plots default date/category axis is 'continuous'
@@ -300,6 +290,12 @@ const EditorPanel = () => {
300
290
  }
301
291
  }, [])
302
292
 
293
+ useEffect(() => {
294
+ if (config.visualizationType !== 'Bar') {
295
+ updateConfig({ ...config, tooltips: { ...config.tooltips, singleSeries: false } })
296
+ }
297
+ }, [config.visualizationType])
298
+
303
299
  const { hasRightAxis } = useRightAxis({ config: config, yMax: config.yAxis.size, data: config.data, updateConfig })
304
300
 
305
301
  const getItemStyle = (isDragging, draggableStyle) => ({
@@ -745,27 +741,49 @@ const EditorPanel = () => {
745
741
  }
746
742
 
747
743
  const section = config.orientation === 'horizontal' ? 'xAxis' : 'yAxis'
748
- const [warningMsg, setWarningMsg] = useState({ maxMsg: '', minMsg: '' })
744
+ const [warningMsg, setWarningMsg] = useState({ maxMsg: '', minMsg: '', rightMaxMessage: '', minMsgRight: '' })
749
745
 
750
746
  const validateMaxValue = () => {
751
747
  const enteredValue = config[section].max
748
+ const enteredRightMax = config[section].rightMax
749
+
752
750
  let message = ''
751
+ let rightMaxMessage = ''
752
+
753
+ if (config.visualizationType !== 'Combo') {
754
+ switch (true) {
755
+ case enteredValue && parseFloat(enteredValue) < parseFloat(maxValue) && existPositiveValue:
756
+ message = 'Max value must be more than ' + maxValue
757
+ break
758
+ case enteredValue && parseFloat(enteredValue) < 0 && !existPositiveValue:
759
+ message = 'Value must be more than or equal to 0'
760
+ break
761
+ default:
762
+ message = ''
763
+ }
764
+ }
753
765
 
754
- switch (true) {
755
- case enteredValue && parseFloat(enteredValue) < parseFloat(maxValue) && existPositiveValue:
756
- message = 'Max value must be more than ' + maxValue
757
- break
758
- case enteredValue && parseFloat(enteredValue) < 0 && !existPositiveValue:
759
- message = 'Value must be more than or equal to 0'
760
- break
761
- default:
762
- message = ''
766
+ if (config.visualizationType === 'Combo') {
767
+ switch (true) {
768
+ case enteredValue && parseFloat(enteredValue) < leftMax:
769
+ message = 'Max value must be more than ' + leftMax
770
+ break
771
+ case enteredRightMax && parseFloat(enteredRightMax) < rightMax:
772
+ rightMaxMessage = 'Max value must be more than ' + rightMax
773
+ break
774
+ case enteredValue && parseFloat(enteredValue) < 0 && !existPositiveValue:
775
+ message = 'Value must be more than or equal to 0'
776
+ break
777
+ default:
778
+ message = ''
779
+ }
763
780
  }
764
- setWarningMsg(prevMsg => ({ ...prevMsg, maxMsg: message }))
781
+
782
+ setWarningMsg(prevMsg => ({ ...prevMsg, maxMsg: message, rightMaxMessage: rightMaxMessage }))
765
783
  }
766
784
 
767
785
  const validateMinValue = () => {
768
- const enteredValue = config[section].min
786
+ const enteredValue = parseFloat(config[section].min)
769
787
  let minVal = Number(minValue)
770
788
  let message = ''
771
789
 
@@ -773,19 +791,19 @@ const EditorPanel = () => {
773
791
  case config.useLogScale && ['Line', 'Combo', 'Bar'].includes(config.visualizationType) && enteredValue < 0:
774
792
  message = 'Negative numbers are not supported in logarithmic scale'
775
793
  break
776
- case (config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && enteredValue && parseFloat(enteredValue) > minVal:
794
+ case (config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && enteredValue > minVal:
777
795
  message = 'Value should not exceed ' + minValue
778
796
  break
779
- case config.visualizationType === 'Combo' && isAllLine && enteredValue && parseFloat(enteredValue) > minVal:
797
+ case config.visualizationType === 'Combo' && isAllLine && enteredValue > minVal:
780
798
  message = 'Value should not exceed ' + minValue
781
799
  break
782
- case (config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && enteredValue && minVal > 0 && parseFloat(enteredValue) > 0:
800
+ case (config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && minVal > 0 && enteredValue > 0:
783
801
  message = config.useLogScale ? 'Value must be equal to 0' : 'Value must be less than or equal to 0'
784
802
  break
785
- case config.visualizationType === 'Deviation Bar' && parseFloat(enteredValue) >= Math.min(minVal, config.xAxis.target):
803
+ case config.visualizationType === 'Deviation Bar' && enteredValue >= Math.min(minVal, config.xAxis.target):
786
804
  message = 'Value must be less than ' + Math.min(minVal, config.xAxis.target)
787
805
  break
788
- case config.visualizationType !== 'Deviation Bar' && enteredValue && minVal < 0 && parseFloat(enteredValue) > minVal:
806
+ case config.visualizationType !== 'Deviation Bar' && enteredValue && minVal < 0 && enteredValue > minVal:
789
807
  message = 'Value should not exceed ' + minValue
790
808
  break
791
809
  default:
@@ -840,7 +858,7 @@ const EditorPanel = () => {
840
858
  ]
841
859
 
842
860
  if (config.data && config.series) {
843
- Object.keys(config.data[0]).map(colName => {
861
+ Object.keys(config.data?.[0] || []).map(colName => {
844
862
  // OMIT ANY COLUMNS THAT ARE IN DATA SERIES!
845
863
  const found = config?.series.some(series => series.dataKey === colName)
846
864
  if (colName !== config.xAxis.dataKey && !found) {
@@ -997,7 +1015,7 @@ const EditorPanel = () => {
997
1015
  {undefined === config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error />}
998
1016
  <button className={displayPanel ? `editor-toggle` : `editor-toggle collapsed`} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick}></button>
999
1017
  <section className={`${displayPanel ? 'editor-panel cove' : 'hidden editor-panel cove'}${isDashboard ? ' dashboard' : ''}`}>
1000
- <div aria-level='2' role='heading' className='heading-2'>
1018
+ <div aria-level={2} role='heading' className='heading-2'>
1001
1019
  Configure Chart
1002
1020
  </div>
1003
1021
  <section className='form-container'>
@@ -1092,7 +1110,7 @@ const EditorPanel = () => {
1092
1110
  />
1093
1111
 
1094
1112
  <TextField
1095
- type='text'
1113
+ type='textarea'
1096
1114
  value={config.description}
1097
1115
  fieldName='description'
1098
1116
  label='Subtext/Citation'
@@ -1132,7 +1150,7 @@ const EditorPanel = () => {
1132
1150
  {visSupportsChartHeight() && config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
1133
1151
  </AccordionItemPanel>
1134
1152
  </AccordionItem>
1135
- {config.visualizationType === 'Forest Plot' && <ForestPlotSettings />}
1153
+ {config.visualizationType === 'Forest Plot' && <Panels.ForestPlot name='Forest Plot Settings' editColumn={editColumn} setCategoryAxis={setCategoryAxis} />}
1136
1154
  {config.visualizationType !== 'Pie' && config.visualizationType !== 'Forest Plot' && (
1137
1155
  <AccordionItem>
1138
1156
  <AccordionItemHeading>
@@ -1155,7 +1173,7 @@ const EditorPanel = () => {
1155
1173
  options={getColumns()}
1156
1174
  />
1157
1175
  {config.series && config.series.length !== 0 && (
1158
- <Series.Wrapper getColumns={getColumns}>
1176
+ <Panels.Series.Wrapper getColumns={getColumns}>
1159
1177
  <fieldset>
1160
1178
  <legend className='edit-label float-left'>Displaying</legend>
1161
1179
  <Tooltip style={{ textTransform: 'none' }}>
@@ -1174,17 +1192,16 @@ const EditorPanel = () => {
1174
1192
  {provided => {
1175
1193
  return (
1176
1194
  <ul {...provided.droppableProps} className='series-list' ref={provided.innerRef}>
1177
- <Series.List series={config.series} getItemStyle={getItemStyle} sortableItemStyles={sortableItemStyles} chartsWithOptions={chartsWithOptions} />
1195
+ <Panels.Series.List series={config.series} getItemStyle={getItemStyle} sortableItemStyles={sortableItemStyles} chartsWithOptions={chartsWithOptions} />
1178
1196
  {provided.placeholder}
1179
1197
  </ul>
1180
1198
  )
1181
1199
  }}
1182
1200
  </Droppable>
1183
1201
  </DragDropContext>
1184
- </Series.Wrapper>
1202
+ </Panels.Series.Wrapper>
1185
1203
  )}
1186
1204
  </>
1187
-
1188
1205
  {config.series && config.series.length <= 1 && config.visualizationType === 'Bar' && (
1189
1206
  <>
1190
1207
  <span className='divider-heading'>Confidence Keys</span>
@@ -1192,8 +1209,9 @@ const EditorPanel = () => {
1192
1209
  <Select value={config.confidenceKeys.lower || ''} section='confidenceKeys' fieldName='lower' label='Lower' updateField={updateField} initial='Select' options={getColumns()} />
1193
1210
  </>
1194
1211
  )}
1195
-
1196
1212
  {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']} />}
1213
+ {/* {visHasDataSuppression() && <DataSuppression config={config} updateConfig={updateConfig} data={data} />} */}
1214
+ {config.visualizationType === 'Line' && <PreliminaryData config={config} updateConfig={updateConfig} data={data} />}
1197
1215
  </AccordionItemPanel>
1198
1216
  </AccordionItem>
1199
1217
  )}
@@ -1367,9 +1385,11 @@ const EditorPanel = () => {
1367
1385
  {config.visualizationType !== 'Pie' && (
1368
1386
  <>
1369
1387
  <TextField value={config.yAxis.label} section='yAxis' fieldName='label' label='Label' updateField={updateField} />
1370
- {config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && config.visualizationType !== 'Box Plot' && <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />}
1388
+ {config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && !['Box Plot', 'Deviation Bar', 'Forest Plot'].includes(config.visualizationType) && (
1389
+ <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />
1390
+ )}
1371
1391
  <TextField value={config.yAxis.numTicks} placeholder='Auto' type='number' section='yAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1372
- {config.visualizationType === 'Paired Bar' && <TextField value={config.yAxis.tickRotation || 0} type='number' min='0' section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1392
+ {config.visualizationType === 'Paired Bar' && <TextField value={config.yAxis.tickRotation || 0} type='number' min={0} section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1373
1393
  <TextField
1374
1394
  value={config.yAxis.size}
1375
1395
  type='number'
@@ -1390,12 +1410,12 @@ const EditorPanel = () => {
1390
1410
  }
1391
1411
  />
1392
1412
  {config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
1393
- {(config.orientation === 'vertical' || !config.isResponsiveTicks) && <TextField value={config.yAxis.tickRotation} type='number' min='0' section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1413
+ {(config.orientation === 'vertical' || !config.isResponsiveTicks) && <TextField value={config.yAxis.tickRotation} type='number' min={0} section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1394
1414
  {config.isResponsiveTicks && config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && (
1395
1415
  <TextField
1396
1416
  value={config.xAxis.maxTickRotation}
1397
1417
  type='number'
1398
- min='0'
1418
+ min={0}
1399
1419
  section='xAxis'
1400
1420
  fieldName='maxTickRotation'
1401
1421
  label='Max Tick Rotation'
@@ -1419,7 +1439,7 @@ const EditorPanel = () => {
1419
1439
  {config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
1420
1440
  {visSupportsValueAxisGridLines() && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Show Gridlines' updateField={updateField} />}
1421
1441
  <CheckBox value={config.yAxis.enablePadding} section='yAxis' fieldName='enablePadding' label='Add Padding to Value Axis Scale' updateField={updateField} />
1422
- {config.visualizationSubType === 'regular' && <CheckBox value={config.useLogScale} fieldName='useLogScale' label='use logarithmic scale' updateField={updateField} />}
1442
+ {config.visualizationSubType === 'regular' && config.visualizationType !== 'Forest Plot' && <CheckBox value={config.useLogScale} fieldName='useLogScale' label='use logarithmic scale' updateField={updateField} />}
1423
1443
  </>
1424
1444
  )}
1425
1445
  <span className='divider-heading'>Number Formatting</span>
@@ -1486,9 +1506,9 @@ const EditorPanel = () => {
1486
1506
  {visSupportsValueAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
1487
1507
  {visSupportsValueAxisLabels() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
1488
1508
  {visSupportsValueAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
1489
- <TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='max value' type='number' placeholder='Auto' updateField={updateField} />
1509
+ {visSupportsValueAxisMax() && <TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='max value' type='number' placeholder='Auto' updateField={updateField} />}
1490
1510
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1491
- <TextField value={config.xAxis.min} section='xAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />
1511
+ {visSupportsValueAxisMin() && <TextField value={config.xAxis.min} section='xAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />}
1492
1512
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1493
1513
  {config.visualizationType === 'Deviation Bar' && (
1494
1514
  <>
@@ -1505,9 +1525,9 @@ const EditorPanel = () => {
1505
1525
  <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1506
1526
  <CheckBox value={config.yAxis.hideTicks} section='yAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1507
1527
 
1508
- <TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='max value' placeholder='Auto' updateField={updateField} />
1528
+ <TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='left axis max value' placeholder='Auto' updateField={updateField} />
1509
1529
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1510
- <TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />
1530
+ <TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='left axis min value' placeholder='Auto' updateField={updateField} />
1511
1531
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1512
1532
  </>
1513
1533
  )
@@ -1625,7 +1645,7 @@ const EditorPanel = () => {
1625
1645
  onClick={e => {
1626
1646
  e.preventDefault()
1627
1647
  const anchors = [...config.yAxis.anchors]
1628
- anchors.push({})
1648
+ anchors.push({} as Anchor)
1629
1649
  updateConfig({
1630
1650
  ...config,
1631
1651
  yAxis: {
@@ -1751,7 +1771,7 @@ const EditorPanel = () => {
1751
1771
  onClick={e => {
1752
1772
  e.preventDefault()
1753
1773
  const anchors = [...config.xAxis.anchors]
1754
- anchors.push({})
1774
+ anchors.push({} as Anchor)
1755
1775
  updateConfig({
1756
1776
  ...config,
1757
1777
  xAxis: {
@@ -1826,28 +1846,60 @@ const EditorPanel = () => {
1826
1846
  <CheckBox value={config.yAxis.rightHideAxis} section='yAxis' fieldName='rightHideAxis' label='Hide Axis' updateField={updateField} />
1827
1847
  <CheckBox value={config.yAxis.rightHideLabel} section='yAxis' fieldName='rightHideLabel' label='Hide Label' updateField={updateField} />
1828
1848
  <CheckBox value={config.yAxis.rightHideTicks} section='yAxis' fieldName='rightHideTicks' label='Hide Ticks' updateField={updateField} />
1849
+
1850
+ <TextField value={config.yAxis.max} section='yAxis' fieldName='rightMax' type='number' label='right axis max value' placeholder='Auto' updateField={updateField} />
1851
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.rightMaxMessage}</span>
1852
+ <TextField value={config.yAxis.min} section='yAxis' fieldName='rightMin' type='number' label='right axis min value' placeholder='Auto' updateField={updateField} />
1853
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1829
1854
  </AccordionItemPanel>
1830
1855
  </AccordionItem>
1831
1856
  )}
1832
- <AccordionItem>
1833
- <AccordionItemHeading>
1834
- <AccordionItemButton>
1835
- {config.visualizationType === 'Pie' ? 'Segments' : 'Date/Category Axis'}
1836
- {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1837
- </AccordionItemButton>
1838
- </AccordionItemHeading>
1839
- <AccordionItemPanel>
1840
- {config.visualizationType !== 'Pie' && (
1841
- <>
1842
- {config.visualizationType !== 'Forest Plot' && (
1843
- <Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={config.visualizationType !== 'Scatter Plot' ? ['categorical', 'date'] : ['categorical', 'continuous', 'date']} />
1844
- )}
1845
- <CheckBox value={config.xAxis.sortDates} section='xAxis' fieldName='sortDates' label='Force Date Scale (Sort Dates)' updateField={updateField} />{' '}
1857
+ {visSupportsDateCategoryAxis() && (
1858
+ <AccordionItem>
1859
+ <AccordionItemHeading>
1860
+ <AccordionItemButton>
1861
+ {config.visualizationType === 'Pie' ? 'Segments' : 'Date/Category Axis'}
1862
+ {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1863
+ </AccordionItemButton>
1864
+ </AccordionItemHeading>
1865
+ <AccordionItemPanel>
1866
+ {config.visualizationType !== 'Pie' && (
1867
+ <>
1868
+ {config.visualizationType !== 'Forest Plot' && (
1869
+ <>
1870
+ <Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={config.visualizationType !== 'Scatter Plot' ? ['categorical', 'date'] : ['categorical', 'continuous', 'date']} />
1871
+ <CheckBox value={config.xAxis.sortDates} section='xAxis' fieldName='sortDates' label='Force Date Scale (Sort Dates)' updateField={updateField} />{' '}
1872
+ </>
1873
+ )}
1874
+ <Select
1875
+ value={config.xAxis.dataKey || setCategoryAxis() || ''}
1876
+ section='xAxis'
1877
+ fieldName='dataKey'
1878
+ label='Data Key'
1879
+ initial='Select'
1880
+ required={true}
1881
+ updateField={updateField}
1882
+ options={getColumns(false)}
1883
+ tooltip={
1884
+ <Tooltip style={{ textTransform: 'none' }}>
1885
+ <Tooltip.Target>
1886
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1887
+ </Tooltip.Target>
1888
+ <Tooltip.Content>
1889
+ <p>Select the column or row containing the categories or dates for this axis. </p>
1890
+ </Tooltip.Content>
1891
+ </Tooltip>
1892
+ }
1893
+ />
1894
+ </>
1895
+ )}
1896
+
1897
+ {config.visualizationType === 'Pie' && (
1846
1898
  <Select
1847
- value={config.xAxis.dataKey || setCategoryAxis() || ''}
1899
+ value={config.xAxis.dataKey || ''}
1848
1900
  section='xAxis'
1849
1901
  fieldName='dataKey'
1850
- label='Data Key'
1902
+ label='Segment Labels'
1851
1903
  initial='Select'
1852
1904
  required={true}
1853
1905
  updateField={updateField}
@@ -1858,86 +1910,169 @@ const EditorPanel = () => {
1858
1910
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1859
1911
  </Tooltip.Target>
1860
1912
  <Tooltip.Content>
1861
- <p>Select the column or row containing the categories or dates for this axis. </p>
1913
+ <p>Select the source row or column that contains the segment labels. Depending on the data structure, it may be listed as "Key."</p>
1862
1914
  </Tooltip.Content>
1863
1915
  </Tooltip>
1864
1916
  }
1865
1917
  />
1866
- </>
1867
- )}
1918
+ )}
1868
1919
 
1869
- {config.visualizationType === 'Pie' && (
1870
- <Select
1871
- value={config.xAxis.dataKey || ''}
1872
- section='xAxis'
1873
- fieldName='dataKey'
1874
- label='Segment Labels'
1875
- initial='Select'
1876
- required={true}
1877
- updateField={updateField}
1878
- options={getColumns(false)}
1879
- tooltip={
1880
- <Tooltip style={{ textTransform: 'none' }}>
1881
- <Tooltip.Target>
1882
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1883
- </Tooltip.Target>
1884
- <Tooltip.Content>
1885
- <p>Select the source row or column that contains the segment labels. Depending on the data structure, it may be listed as "Key."</p>
1886
- </Tooltip.Content>
1887
- </Tooltip>
1888
- }
1889
- />
1890
- )}
1920
+ {config.visualizationType !== 'Pie' && (
1921
+ <>
1922
+ <TextField value={config.xAxis.label} section='xAxis' fieldName='label' label='Label' updateField={updateField} />
1891
1923
 
1892
- {config.visualizationType !== 'Pie' && (
1893
- <>
1894
- <TextField value={config.xAxis.label} section='xAxis' fieldName='label' label='Label' updateField={updateField} />
1924
+ {config.xAxis.type === 'continuous' && (
1925
+ <>
1926
+ <TextField
1927
+ value={config.dataFormat.bottomPrefix}
1928
+ section='dataFormat'
1929
+ fieldName='bottomPrefix'
1930
+ label='Prefix'
1931
+ updateField={updateField}
1932
+ tooltip={
1933
+ <Tooltip style={{ textTransform: 'none' }}>
1934
+ <Tooltip.Target>
1935
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1936
+ </Tooltip.Target>
1937
+ <Tooltip.Content>
1938
+ <p>Enter a data suffix (such as "%"), if applicable.</p>
1939
+ </Tooltip.Content>
1940
+ </Tooltip>
1941
+ }
1942
+ />
1943
+
1944
+ <TextField
1945
+ value={config.dataFormat.bottomSuffix}
1946
+ section='dataFormat'
1947
+ fieldName='bottomSuffix'
1948
+ label='Suffix'
1949
+ updateField={updateField}
1950
+ tooltip={
1951
+ <Tooltip style={{ textTransform: 'none' }}>
1952
+ <Tooltip.Target>
1953
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1954
+ </Tooltip.Target>
1955
+ <Tooltip.Content>
1956
+ <p>Enter a data suffix (such as "%"), if applicable.</p>
1957
+ </Tooltip.Content>
1958
+ </Tooltip>
1959
+ }
1960
+ />
1961
+
1962
+ <CheckBox
1963
+ value={config.dataFormat.bottomAbbreviated}
1964
+ section='dataFormat'
1965
+ fieldName='bottomAbbreviated'
1966
+ label='Abbreviate Axis Values'
1967
+ updateField={updateField}
1968
+ tooltip={
1969
+ <Tooltip style={{ textTransform: 'none' }}>
1970
+ <Tooltip.Target>
1971
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1972
+ </Tooltip.Target>
1973
+ <Tooltip.Content>
1974
+ <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
1975
+ </Tooltip.Content>
1976
+ </Tooltip>
1977
+ }
1978
+ />
1979
+ </>
1980
+ )}
1895
1981
 
1896
- {config.xAxis.type === 'continuous' && (
1897
- <>
1898
- <TextField
1899
- value={config.dataFormat.bottomPrefix}
1900
- section='dataFormat'
1901
- fieldName='bottomPrefix'
1902
- label='Prefix'
1903
- updateField={updateField}
1904
- tooltip={
1905
- <Tooltip style={{ textTransform: 'none' }}>
1906
- <Tooltip.Target>
1907
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1908
- </Tooltip.Target>
1909
- <Tooltip.Content>
1910
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1911
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1912
- </Tooltip.Content>
1913
- </Tooltip>
1914
- }
1915
- />
1982
+ {config.xAxis.type === 'date' && (
1983
+ <>
1984
+ <p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
1985
+ Format how charts should parse and display your dates using{' '}
1986
+ <a href='https://github.com/d3/d3-time-format#locale_format' target='_blank' rel='noreferrer'>
1987
+ these guidelines
1988
+ </a>
1989
+ .
1990
+ </p>
1991
+ <TextField value={config.xAxis.dateParseFormat} section='xAxis' fieldName='dateParseFormat' placeholder='Ex. %Y-%m-%d' label='Date Parse Format' updateField={updateField} />
1992
+ <TextField value={config.xAxis.dateDisplayFormat} section='xAxis' fieldName='dateDisplayFormat' placeholder='Ex. %Y-%m-%d' label='Date Display Format' updateField={updateField} />
1993
+ </>
1994
+ )}
1916
1995
 
1917
- <TextField
1918
- value={config.dataFormat.bottomSuffix}
1919
- section='dataFormat'
1920
- fieldName='bottomSuffix'
1921
- label='Suffix'
1922
- updateField={updateField}
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
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1930
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1931
- </Tooltip.Content>
1932
- </Tooltip>
1933
- }
1934
- />
1996
+ <CheckBox
1997
+ value={config.exclusions.active}
1998
+ section='exclusions'
1999
+ fieldName='active'
2000
+ label={config.xAxis.type === 'date' ? 'Limit by start and/or end dates' : 'Exclude one or more values'}
2001
+ tooltip={
2002
+ <Tooltip style={{ textTransform: 'none' }}>
2003
+ <Tooltip.Target>
2004
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2005
+ </Tooltip.Target>
2006
+ <Tooltip.Content>
2007
+ <p>When this option is checked, you can select source-file values for exclusion from the date/category axis. </p>
2008
+ </Tooltip.Content>
2009
+ </Tooltip>
2010
+ }
2011
+ updateField={updateField}
2012
+ />
2013
+ {/* {visHasBrushChart && <CheckBox value={config.brush.active} section='brush' fieldName='active' label='Brush Slider ' updateField={updateField} />} */}
2014
+
2015
+ {config.exclusions.active && (
2016
+ <>
2017
+ {config.xAxis.type === 'categorical' && (
2018
+ <>
2019
+ {config.exclusions.keys.length > 0 && (
2020
+ <>
2021
+ <fieldset>
2022
+ <legend className='edit-label'>Excluded Keys</legend>
2023
+ </fieldset>
2024
+ <ExclusionsList />
2025
+ </>
2026
+ )}
1935
2027
 
1936
- <CheckBox
1937
- value={config.dataFormat.bottomAbbreviated}
1938
- section='dataFormat'
1939
- fieldName='bottomAbbreviated'
1940
- label='Abbreviate Axis Values'
2028
+ <Select
2029
+ fieldName='visualizationType'
2030
+ label='Add Exclusion'
2031
+ initial='Select'
2032
+ onChange={e => {
2033
+ if (e.target.value !== '' && e.target.value !== 'Select') {
2034
+ addNewExclusion(e.target.value)
2035
+ }
2036
+ e.target.value = ''
2037
+ }}
2038
+ options={getDataValues(config.xAxis.dataKey, true)}
2039
+ />
2040
+ </>
2041
+ )}
2042
+
2043
+ {config.xAxis.type === 'date' && (
2044
+ <>
2045
+ <TextField type='date' section='exclusions' fieldName='dateStart' label='Start Date' updateField={updateField} value={config.exclusions.dateStart || ''} />
2046
+ <TextField type='date' section='exclusions' fieldName='dateEnd' label='End Date' updateField={updateField} value={config.exclusions.dateEnd || ''} />
2047
+ </>
2048
+ )}
2049
+ </>
2050
+ )}
2051
+
2052
+ {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} />}
2053
+ {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} />}
2054
+
2055
+ {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
2056
+ {/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
2057
+ {(config.xAxis.type === 'continuous' || config.forestPlot.type === 'Logarithmic') && (
2058
+ <>
2059
+ <CheckBox value={config.dataFormat.bottomCommas} section='dataFormat' fieldName='bottomCommas' label='Add commas' updateField={updateField} />
2060
+ <TextField value={config.dataFormat.bottomRoundTo} type='number' section='dataFormat' fieldName='bottomRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
2061
+ </>
2062
+ )}
2063
+ {visSupportsResponsiveTicks() && config.orientation === 'vertical' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
2064
+ {(config.orientation === 'horizontal' || !config.isResponsiveTicks) && visSupportsDateCategoryTickRotation() && (
2065
+ <TextField value={config.xAxis.tickRotation} type='number' min={0} section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />
2066
+ )}
2067
+ {config.orientation === 'vertical' && config.isResponsiveTicks && config.visualizationType !== 'Paired Bar' && (
2068
+ <TextField
2069
+ value={config.xAxis.maxTickRotation}
2070
+ type='number'
2071
+ min={0}
2072
+ section='xAxis'
2073
+ fieldName='maxTickRotation'
2074
+ label='Max Tick Rotation'
2075
+ className='number-narrow'
1941
2076
  updateField={updateField}
1942
2077
  tooltip={
1943
2078
  <Tooltip style={{ textTransform: 'none' }}>
@@ -1945,108 +2080,75 @@ const EditorPanel = () => {
1945
2080
  <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1946
2081
  </Tooltip.Target>
1947
2082
  <Tooltip.Content>
1948
- <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
2083
+ <p>Degrees ticks will be rotated if values overlap, especially in smaller viewports.</p>
1949
2084
  </Tooltip.Content>
1950
2085
  </Tooltip>
1951
2086
  }
1952
2087
  />
1953
- </>
1954
- )}
1955
-
1956
- {config.xAxis.type === 'date' && (
1957
- <>
1958
- <p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
1959
- Format how charts should parse and display your dates using{' '}
1960
- <a href='https://github.com/d3/d3-time-format#locale_format' target='_blank' rel='noreferrer'>
1961
- these guidelines
1962
- </a>
1963
- .
1964
- </p>
1965
- <TextField value={config.xAxis.dateParseFormat} section='xAxis' fieldName='dateParseFormat' placeholder='Ex. %Y-%m-%d' label='Date Parse Format' updateField={updateField} />
1966
- <TextField value={config.xAxis.dateDisplayFormat} section='xAxis' fieldName='dateDisplayFormat' placeholder='Ex. %Y-%m-%d' label='Date Display Format' updateField={updateField} />
1967
- </>
1968
- )}
2088
+ )}
1969
2089
 
1970
- <CheckBox
1971
- value={config.exclusions.active}
1972
- section='exclusions'
1973
- fieldName='active'
1974
- label={config.xAxis.type === 'date' ? 'Limit by start and/or end dates' : 'Exclude one or more values'}
1975
- tooltip={
1976
- <Tooltip style={{ textTransform: 'none' }}>
1977
- <Tooltip.Target>
1978
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1979
- </Tooltip.Target>
1980
- <Tooltip.Content>
1981
- <p>When this option is checked, you can select source-file values for exclusion from the date/category axis. </p>
1982
- </Tooltip.Content>
1983
- </Tooltip>
1984
- }
1985
- updateField={updateField}
1986
- />
2090
+ {config.orientation === 'horizontal' ? (
2091
+ <>
2092
+ {visSupportsDateCategoryAxisLine() && <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2093
+ {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
2094
+ </>
2095
+ ) : (
2096
+ <>
2097
+ {visSupportsDateCategoryAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2098
+ {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
2099
+ {visSupportsDateCategoryAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
2100
+ </>
2101
+ )}
1987
2102
 
1988
- {config.exclusions.active && (
1989
- <>
1990
- {config.xAxis.type === 'categorical' && (
1991
- <>
1992
- {config.exclusions.keys.length > 0 && (
1993
- <>
1994
- <fieldset>
1995
- <legend className='edit-label'>Excluded Keys</legend>
1996
- </fieldset>
1997
- <ExclusionsList />
1998
- </>
1999
- )}
2103
+ {config.series?.length === 1 && config.visualizationType === 'Bar' && (
2104
+ <>
2105
+ {/* HIGHLIGHTED BARS */}
2106
+ <label htmlFor='barHighlight'>Bar Highlighting</label>
2107
+ {config.series.length === 1 &&
2108
+ highlightedBarValues.map((highlightedBarValue, i) => (
2109
+ <fieldset>
2110
+ <div className='edit-block' key={`highlighted-bar-${i}`}>
2111
+ <button className='remove-column' onClick={e => handleRemoveHighlightedBar(e, i)}>
2112
+ Remove
2113
+ </button>
2114
+ <p>Highlighted Bar {i + 1}</p>
2115
+ <label>
2116
+ <span className='edit-label column-heading'>Value</span>
2117
+ <select value={config.highlightedBarValues[i].value} onChange={e => handleUpdateHighlightedBar(e, i)}>
2118
+ <option value=''>- Select Value -</option>
2119
+ {highlightedSeriesValues && [...new Set(highlightedSeriesValues)].sort().map(option => <option key={`special-class-value-option-${i}-${option}`}>{option}</option>)}
2120
+ </select>
2121
+ </label>
2122
+ <label>
2123
+ <span className='edit-label column-heading'>Color</span>
2124
+ <input type='text' value={config.highlightedBarValues[i].color ? config.highlightedBarValues[i].color : ''} onChange={e => handleUpdateHighlightedBarColor(e, i)} />
2125
+ </label>
2126
+ <label>
2127
+ <span className='edit-label column-heading'>Border Width</span>
2128
+ <input max='5' min='0' type='number' value={config.highlightedBarValues[i].borderWidth ? config.highlightedBarValues[i].borderWidth : ''} onChange={e => handleUpdateHighlightedBorderWidth(e, i)} />
2129
+ </label>
2130
+ <label>
2131
+ <span className='edit-label column-heading'>Legend Label</span>
2132
+ <input type='text' value={config.highlightedBarValues[i].legendLabel ? config.highlightedBarValues[i].legendLabel : ''} onChange={e => handleHighlightedBarLegendLabel(e, i)} />
2133
+ </label>
2134
+ </div>
2135
+ </fieldset>
2136
+ ))}
2137
+ <button className='btn full-width' onClick={e => handleAddNewHighlightedBar(e)}>
2138
+ Add Highlighted Bar
2139
+ </button>
2140
+ </>
2141
+ )}
2142
+ </>
2143
+ )}
2000
2144
 
2001
- <Select
2002
- fieldName='visualizationType'
2003
- label='Add Exclusion'
2004
- initial='Select'
2005
- onChange={e => {
2006
- if (e.target.value !== '' && e.target.value !== 'Select') {
2007
- addNewExclusion(e.target.value)
2008
- }
2009
- e.target.value = ''
2010
- }}
2011
- options={getDataValues(config.xAxis.dataKey, true)}
2012
- />
2013
- </>
2014
- )}
2015
-
2016
- {config.xAxis.type === 'date' && (
2017
- <>
2018
- <TextField type='date' section='exclusions' fieldName='dateStart' label='Start Date' updateField={updateField} value={config.exclusions.dateStart || ''} />
2019
- <TextField type='date' section='exclusions' fieldName='dateEnd' label='End Date' updateField={updateField} value={config.exclusions.dateEnd || ''} />
2020
- </>
2021
- )}
2022
- </>
2023
- )}
2024
-
2025
- {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} />}
2026
- {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} />}
2027
-
2028
- {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
2029
- {/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
2030
-
2031
- {config.xAxis.type === 'continuous' && (
2032
- <>
2033
- <CheckBox value={config.dataFormat.bottomCommas} section='dataFormat' fieldName='bottomCommas' label='Add commas' updateField={updateField} />
2034
- <TextField value={config.dataFormat.bottomRoundTo} type='number' section='dataFormat' fieldName='bottomRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
2035
- </>
2036
- )}
2037
- {visSupportsResponsiveTicks() && config.orientation === 'vertical' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
2038
- {(config.orientation === 'horizontal' || !config.isResponsiveTicks) && visSupportsDateCategoryTickRotation() && (
2039
- <TextField value={config.xAxis.tickRotation} type='number' min='0' section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />
2040
- )}
2041
- {config.orientation === 'vertical' && config.isResponsiveTicks && config.visualizationType !== 'Paired Bar' && (
2042
- <TextField
2043
- value={config.xAxis.maxTickRotation}
2044
- type='number'
2045
- min='0'
2046
- section='xAxis'
2047
- fieldName='maxTickRotation'
2048
- label='Max Tick Rotation'
2049
- className='number-narrow'
2145
+ {config.visualizationType === 'Pie' && (
2146
+ <>
2147
+ <CheckBox
2148
+ value={config.exclusions.active}
2149
+ section='exclusions'
2150
+ fieldName='active'
2151
+ label={'Exclude one or more values'}
2050
2152
  updateField={updateField}
2051
2153
  tooltip={
2052
2154
  <Tooltip style={{ textTransform: 'none' }}>
@@ -2054,381 +2156,297 @@ const EditorPanel = () => {
2054
2156
  <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2055
2157
  </Tooltip.Target>
2056
2158
  <Tooltip.Content>
2057
- <p>Degrees ticks will be rotated if values overlap, especially in smaller viewports.</p>
2159
+ <p>When this option is checked, you can select values for exclusion from the pie segments.</p>
2058
2160
  </Tooltip.Content>
2059
2161
  </Tooltip>
2060
2162
  }
2061
2163
  />
2062
- )}
2063
-
2064
- {config.orientation === 'horizontal' ? (
2065
- <>
2066
- {visSupportsDateCategoryAxisLine() && <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2067
- {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
2068
- </>
2069
- ) : (
2070
- <>
2071
- {visSupportsDateCategoryAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2072
- {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
2073
- {visSupportsDateCategoryAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
2074
- </>
2075
- )}
2076
-
2077
- {config.series?.length === 1 && config.visualizationType === 'Bar' && (
2078
- <>
2079
- {/* HIGHLIGHTED BARS */}
2080
- <label htmlFor='barHighlight'>Bar Highlighting</label>
2081
- {config.series.length === 1 &&
2082
- highlightedBarValues.map((highlightedBarValue, i) => (
2083
- <fieldset>
2084
- <div className='edit-block' key={`highlighted-bar-${i}`}>
2085
- <button className='remove-column' onClick={e => handleRemoveHighlightedBar(e, i)}>
2086
- Remove
2087
- </button>
2088
- <p>Highlighted Bar {i + 1}</p>
2089
- <label>
2090
- <span className='edit-label column-heading'>Value</span>
2091
- <select value={config.highlightedBarValues[i].value} onChange={e => handleUpdateHighlightedBar(e, i)}>
2092
- <option value=''>- Select Value -</option>
2093
- {highlightedSeriesValues && [...new Set(highlightedSeriesValues)].sort().map(option => <option key={`special-class-value-option-${i}-${option}`}>{option}</option>)}
2094
- </select>
2095
- </label>
2096
- <label>
2097
- <span className='edit-label column-heading'>Color</span>
2098
- <input type='text' value={config.highlightedBarValues[i].color ? config.highlightedBarValues[i].color : ''} onChange={e => handleUpdateHighlightedBarColor(e, i)} />
2099
- </label>
2100
- <label>
2101
- <span className='edit-label column-heading'>Border Width</span>
2102
- <input max='5' min='0' type='number' value={config.highlightedBarValues[i].borderWidth ? config.highlightedBarValues[i].borderWidth : ''} onChange={e => handleUpdateHighlightedBorderWidth(e, i)} />
2103
- </label>
2104
- <label>
2105
- <span className='edit-label column-heading'>Legend Label</span>
2106
- <input type='text' value={config.highlightedBarValues[i].legendLabel ? config.highlightedBarValues[i].legendLabel : ''} onChange={e => handleHighlightedBarLegendLabel(e, i)} />
2107
- </label>
2108
- </div>
2109
- </fieldset>
2110
- ))}
2111
- <button className='btn full-width' onClick={e => handleAddNewHighlightedBar(e)}>
2112
- Add Highlighted Bar
2113
- </button>
2114
- </>
2115
- )}
2116
- </>
2117
- )}
2164
+ {config.exclusions.active && (
2165
+ <>
2166
+ {config.exclusions.keys.length > 0 && (
2167
+ <>
2168
+ <fieldset>
2169
+ <legend className='edit-label'>Excluded Keys</legend>
2170
+ </fieldset>
2171
+ <ExclusionsList />
2172
+ </>
2173
+ )}
2174
+
2175
+ <Select
2176
+ fieldName='visualizationType'
2177
+ label='Add Exclusion'
2178
+ initial='Select'
2179
+ onChange={e => {
2180
+ if (e.target.value !== '' && e.target.value !== 'Select') {
2181
+ addNewExclusion(e.target.value)
2182
+ }
2183
+ e.target.value = ''
2184
+ }}
2185
+ options={getDataValues(config.xAxis.dataKey, true)}
2186
+ />
2187
+ </>
2188
+ )}
2189
+ </>
2190
+ )}
2118
2191
 
2119
- {config.visualizationType === 'Pie' && (
2120
- <>
2121
- <CheckBox
2122
- value={config.exclusions.active}
2123
- section='exclusions'
2124
- fieldName='active'
2125
- label={'Exclude one or more values'}
2126
- updateField={updateField}
2127
- tooltip={
2128
- <Tooltip style={{ textTransform: 'none' }}>
2129
- <Tooltip.Target>
2130
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2131
- </Tooltip.Target>
2132
- <Tooltip.Content>
2133
- <p>When this option is checked, you can select values for exclusion from the pie segments.</p>
2134
- </Tooltip.Content>
2135
- </Tooltip>
2136
- }
2137
- />
2138
- {config.exclusions.active && (
2139
- <>
2140
- {config.exclusions.keys.length > 0 && (
2141
- <>
2142
- <fieldset>
2143
- <legend className='edit-label'>Excluded Keys</legend>
2144
- </fieldset>
2145
- <ExclusionsList />
2146
- </>
2147
- )}
2148
-
2149
- <Select
2150
- fieldName='visualizationType'
2151
- label='Add Exclusion'
2152
- initial='Select'
2153
- onChange={e => {
2154
- if (e.target.value !== '' && e.target.value !== 'Select') {
2155
- addNewExclusion(e.target.value)
2156
- }
2157
- e.target.value = ''
2158
- }}
2159
- options={getDataValues(config.xAxis.dataKey, true)}
2160
- />
2161
- </>
2162
- )}
2163
- </>
2164
- )}
2192
+ {/* anchors */}
2193
+ {visHasAnchors() && config.orientation !== 'horizontal' && (
2194
+ <div className='edit-block'>
2195
+ <span className='edit-label column-heading'>Anchors</span>
2196
+ <Accordion allowZeroExpanded>
2197
+ {config.xAxis?.anchors?.map((anchor, index) => (
2198
+ <AccordionItem className='series-item series-item--chart' key={`xaxis-anchors-2-${index}`}>
2199
+ <AccordionItemHeading className='series-item__title'>
2200
+ <>
2201
+ <AccordionItemButton className={'accordion__button accordion__button'}>
2202
+ Anchor {index + 1}
2203
+ <button
2204
+ className='series-list__remove'
2205
+ onClick={e => {
2206
+ e.preventDefault()
2207
+ const copiedAnchorGroups = [...config.xAxis.anchors]
2208
+ copiedAnchorGroups.splice(index, 1)
2209
+ updateConfig({
2210
+ ...config,
2211
+ xAxis: {
2212
+ ...config.xAxis,
2213
+ anchors: copiedAnchorGroups
2214
+ }
2215
+ })
2216
+ }}
2217
+ >
2218
+ Remove
2219
+ </button>
2220
+ </AccordionItemButton>
2221
+ </>
2222
+ </AccordionItemHeading>
2223
+ <AccordionItemPanel>
2224
+ <label>
2225
+ <span>Anchor Value</span>
2226
+ <Tooltip style={{ textTransform: 'none' }}>
2227
+ <Tooltip.Target>
2228
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2229
+ </Tooltip.Target>
2230
+ <Tooltip.Content>
2231
+ <p>Enter the value as its shown in the data column</p>
2232
+ </Tooltip.Content>
2233
+ </Tooltip>
2234
+ <input
2235
+ type='text'
2236
+ value={config.xAxis.anchors[index].value ? config.xAxis.anchors[index].value : ''}
2237
+ onChange={e => {
2238
+ e.preventDefault()
2239
+ const copiedAnchors = [...config.xAxis.anchors]
2240
+ copiedAnchors[index].value = e.target.value
2241
+ updateConfig({
2242
+ ...config,
2243
+ xAxis: {
2244
+ ...config.xAxis,
2245
+ anchors: copiedAnchors
2246
+ }
2247
+ })
2248
+ }}
2249
+ />
2250
+ </label>
2165
2251
 
2166
- {/* anchors */}
2167
- {visHasAnchors() && config.orientation !== 'horizontal' && (
2168
- <div className='edit-block'>
2169
- <span className='edit-label column-heading'>Anchors</span>
2170
- <Accordion allowZeroExpanded>
2171
- {config.xAxis?.anchors?.map((anchor, index) => (
2172
- <AccordionItem className='series-item series-item--chart' key={`xaxis-anchors-2-${index}`}>
2173
- <AccordionItemHeading className='series-item__title'>
2174
- <>
2175
- <AccordionItemButton className={'accordion__button accordion__button'}>
2176
- Anchor {index + 1}
2177
- <button
2178
- className='series-list__remove'
2179
- onClick={e => {
2252
+ <label>
2253
+ <span>Anchor Color</span>
2254
+ <input
2255
+ type='text'
2256
+ value={config.xAxis.anchors[index].color ? config.xAxis.anchors[index].color : ''}
2257
+ onChange={e => {
2180
2258
  e.preventDefault()
2181
- const copiedAnchorGroups = [...config.xAxis.anchors]
2182
- copiedAnchorGroups.splice(index, 1)
2259
+ const copiedAnchors = [...config.xAxis.anchors]
2260
+ copiedAnchors[index].color = e.target.value
2183
2261
  updateConfig({
2184
2262
  ...config,
2185
2263
  xAxis: {
2186
2264
  ...config.xAxis,
2187
- anchors: copiedAnchorGroups
2265
+ anchors: copiedAnchors
2266
+ }
2267
+ })
2268
+ }}
2269
+ />
2270
+ </label>
2271
+
2272
+ <label>
2273
+ Anchor Line Style
2274
+ <select
2275
+ value={config.xAxis.anchors[index].lineStyle || ''}
2276
+ onChange={e => {
2277
+ const copiedAnchors = [...config.xAxis.anchors]
2278
+ copiedAnchors[index].lineStyle = e.target.value
2279
+ updateConfig({
2280
+ ...config,
2281
+ xAxis: {
2282
+ ...config.xAxis,
2283
+ anchors: copiedAnchors
2188
2284
  }
2189
2285
  })
2190
2286
  }}
2191
2287
  >
2192
- Remove
2193
- </button>
2194
- </AccordionItemButton>
2195
- </>
2196
- </AccordionItemHeading>
2197
- <AccordionItemPanel>
2198
- <label>
2199
- <span>Anchor Value</span>
2200
- <Tooltip style={{ textTransform: 'none' }}>
2201
- <Tooltip.Target>
2202
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2203
- </Tooltip.Target>
2204
- <Tooltip.Content>
2205
- <p>Enter the value as its shown in the data column</p>
2206
- </Tooltip.Content>
2207
- </Tooltip>
2208
- <input
2209
- type='text'
2210
- value={config.xAxis.anchors[index].value ? config.xAxis.anchors[index].value : ''}
2211
- onChange={e => {
2212
- e.preventDefault()
2213
- const copiedAnchors = [...config.xAxis.anchors]
2214
- copiedAnchors[index].value = e.target.value
2215
- updateConfig({
2216
- ...config,
2217
- xAxis: {
2218
- ...config.xAxis,
2219
- anchors: copiedAnchors
2220
- }
2221
- })
2222
- }}
2223
- />
2224
- </label>
2288
+ <option>Select</option>
2289
+ {lineOptions.map(line => (
2290
+ <option key={line.key}>{line.value}</option>
2291
+ ))}
2292
+ </select>
2293
+ </label>
2294
+ </AccordionItemPanel>
2295
+ </AccordionItem>
2296
+ ))}
2297
+ </Accordion>
2225
2298
 
2226
- <label>
2227
- <span>Anchor Color</span>
2228
- <input
2229
- type='text'
2230
- value={config.xAxis.anchors[index].color ? config.xAxis.anchors[index].color : ''}
2231
- onChange={e => {
2232
- e.preventDefault()
2233
- const copiedAnchors = [...config.xAxis.anchors]
2234
- copiedAnchors[index].color = e.target.value
2235
- updateConfig({
2236
- ...config,
2237
- xAxis: {
2238
- ...config.xAxis,
2239
- anchors: copiedAnchors
2240
- }
2241
- })
2242
- }}
2243
- />
2244
- </label>
2299
+ <button
2300
+ className='btn full-width'
2301
+ onClick={e => {
2302
+ e.preventDefault()
2303
+ const anchors = [...config.xAxis.anchors]
2304
+ anchors.push({} as Anchor)
2305
+ updateConfig({
2306
+ ...config,
2307
+ xAxis: {
2308
+ ...config.xAxis,
2309
+ anchors
2310
+ }
2311
+ })
2312
+ }}
2313
+ >
2314
+ Add Anchor
2315
+ </button>
2316
+ </div>
2317
+ )}
2245
2318
 
2246
- <label>
2247
- Anchor Line Style
2248
- <select
2249
- value={config.xAxis.anchors[index].lineStyle || ''}
2250
- onChange={e => {
2251
- const copiedAnchors = [...config.xAxis.anchors]
2252
- copiedAnchors[index].lineStyle = e.target.value
2253
- updateConfig({
2254
- ...config,
2255
- xAxis: {
2256
- ...config.xAxis,
2257
- anchors: copiedAnchors
2258
- }
2259
- })
2260
- }}
2261
- >
2262
- <option>Select</option>
2263
- {lineOptions.map(line => (
2264
- <option key={line.key}>{line.value}</option>
2265
- ))}
2266
- </select>
2267
- </label>
2268
- </AccordionItemPanel>
2269
- </AccordionItem>
2270
- ))}
2271
- </Accordion>
2272
-
2273
- <button
2274
- className='btn full-width'
2275
- onClick={e => {
2276
- e.preventDefault()
2277
- const anchors = [...config.xAxis.anchors]
2278
- anchors.push({})
2279
- updateConfig({
2280
- ...config,
2281
- xAxis: {
2282
- ...config.xAxis,
2283
- anchors
2284
- }
2285
- })
2286
- }}
2287
- >
2288
- Add Anchor
2289
- </button>
2290
- </div>
2291
- )}
2319
+ {visHasAnchors() && config.orientation === 'horizontal' && (
2320
+ <div className='edit-block'>
2321
+ <span className='edit-label column-heading'>Anchors</span>
2322
+ <Accordion allowZeroExpanded>
2323
+ {config.yAxis?.anchors?.map((anchor, index) => (
2324
+ <AccordionItem className='series-item series-item--chart' key={`accordion-yaxis-anchors-${index}`}>
2325
+ <AccordionItemHeading className='series-item__title'>
2326
+ <>
2327
+ <AccordionItemButton className={'accordion__button accordion__button'}>
2328
+ Anchor {index + 1}
2329
+ <button
2330
+ className='series-list__remove'
2331
+ onClick={e => {
2332
+ e.preventDefault()
2333
+ const copiedAnchorGroups = [...config.yAxis.anchors]
2334
+ copiedAnchorGroups.splice(index, 1)
2335
+ updateConfig({
2336
+ ...config,
2337
+ yAxis: {
2338
+ ...config.yAxis,
2339
+ anchors: copiedAnchorGroups
2340
+ }
2341
+ })
2342
+ }}
2343
+ >
2344
+ Remove
2345
+ </button>
2346
+ </AccordionItemButton>
2347
+ </>
2348
+ </AccordionItemHeading>
2349
+ <AccordionItemPanel>
2350
+ <label>
2351
+ <span>Anchor Value</span>
2352
+ <Tooltip style={{ textTransform: 'none' }}>
2353
+ <Tooltip.Target>
2354
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2355
+ </Tooltip.Target>
2356
+ <Tooltip.Content>
2357
+ <p>Enter the value as its shown in the data column</p>
2358
+ </Tooltip.Content>
2359
+ </Tooltip>
2360
+ <input
2361
+ type='text'
2362
+ value={config.yAxis.anchors[index].value ? config.yAxis.anchors[index].value : ''}
2363
+ onChange={e => {
2364
+ e.preventDefault()
2365
+ const copiedAnchors = [...config.yAxis.anchors]
2366
+ copiedAnchors[index].value = e.target.value
2367
+ updateConfig({
2368
+ ...config,
2369
+ yAxis: {
2370
+ ...config.yAxis,
2371
+ anchors: copiedAnchors
2372
+ }
2373
+ })
2374
+ }}
2375
+ />
2376
+ </label>
2292
2377
 
2293
- {visHasAnchors() && config.orientation === 'horizontal' && (
2294
- <div className='edit-block'>
2295
- <span className='edit-label column-heading'>Anchors</span>
2296
- <Accordion allowZeroExpanded>
2297
- {config.yAxis?.anchors?.map((anchor, index) => (
2298
- <AccordionItem className='series-item series-item--chart' key={`accordion-yaxis-anchors-${index}`}>
2299
- <AccordionItemHeading className='series-item__title'>
2300
- <>
2301
- <AccordionItemButton className={'accordion__button accordion__button'}>
2302
- Anchor {index + 1}
2303
- <button
2304
- className='series-list__remove'
2305
- onClick={e => {
2378
+ <label>
2379
+ <span>Anchor Color</span>
2380
+ <input
2381
+ type='text'
2382
+ value={config.yAxis.anchors[index].color ? config.yAxis.anchors[index].color : ''}
2383
+ onChange={e => {
2306
2384
  e.preventDefault()
2307
- const copiedAnchorGroups = [...config.yAxis.anchors]
2308
- copiedAnchorGroups.splice(index, 1)
2385
+ const copiedAnchors = [...config.yAxis.anchors]
2386
+ copiedAnchors[index].color = e.target.value
2309
2387
  updateConfig({
2310
2388
  ...config,
2311
2389
  yAxis: {
2312
2390
  ...config.yAxis,
2313
- anchors: copiedAnchorGroups
2391
+ anchors: copiedAnchors
2314
2392
  }
2315
2393
  })
2316
2394
  }}
2317
- >
2318
- Remove
2319
- </button>
2320
- </AccordionItemButton>
2321
- </>
2322
- </AccordionItemHeading>
2323
- <AccordionItemPanel>
2324
- <label>
2325
- <span>Anchor Value</span>
2326
- <Tooltip style={{ textTransform: 'none' }}>
2327
- <Tooltip.Target>
2328
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2329
- </Tooltip.Target>
2330
- <Tooltip.Content>
2331
- <p>Enter the value as its shown in the data column</p>
2332
- </Tooltip.Content>
2333
- </Tooltip>
2334
- <input
2335
- type='text'
2336
- value={config.yAxis.anchors[index].value ? config.yAxis.anchors[index].value : ''}
2337
- onChange={e => {
2338
- e.preventDefault()
2339
- const copiedAnchors = [...config.yAxis.anchors]
2340
- copiedAnchors[index].value = e.target.value
2341
- updateConfig({
2342
- ...config,
2343
- yAxis: {
2344
- ...config.yAxis,
2345
- anchors: copiedAnchors
2346
- }
2347
- })
2348
- }}
2349
- />
2350
- </label>
2395
+ />
2396
+ </label>
2351
2397
 
2352
- <label>
2353
- <span>Anchor Color</span>
2354
- <input
2355
- type='text'
2356
- value={config.yAxis.anchors[index].color ? config.yAxis.anchors[index].color : ''}
2357
- onChange={e => {
2358
- e.preventDefault()
2359
- const copiedAnchors = [...config.yAxis.anchors]
2360
- copiedAnchors[index].color = e.target.value
2361
- updateConfig({
2362
- ...config,
2363
- yAxis: {
2364
- ...config.yAxis,
2365
- anchors: copiedAnchors
2366
- }
2367
- })
2368
- }}
2369
- />
2370
- </label>
2398
+ <label>
2399
+ Anchor Line Style
2400
+ <select
2401
+ value={config.yAxis.anchors[index].lineStyle || ''}
2402
+ onChange={e => {
2403
+ const copiedAnchors = [...config.yAxis.anchors]
2404
+ copiedAnchors[index].lineStyle = e.target.value
2405
+ updateConfig({
2406
+ ...config,
2407
+ yAxis: {
2408
+ ...config.yAxis,
2409
+ anchors: copiedAnchors
2410
+ }
2411
+ })
2412
+ }}
2413
+ >
2414
+ <option>Select</option>
2415
+ {lineOptions.map(line => (
2416
+ <option key={line.key}>{line.value}</option>
2417
+ ))}
2418
+ </select>
2419
+ </label>
2420
+ </AccordionItemPanel>
2421
+ </AccordionItem>
2422
+ ))}
2423
+ </Accordion>
2371
2424
 
2372
- <label>
2373
- Anchor Line Style
2374
- <select
2375
- value={config.yAxis.anchors[index].lineStyle || ''}
2376
- onChange={e => {
2377
- const copiedAnchors = [...config.yAxis.anchors]
2378
- copiedAnchors[index].lineStyle = e.target.value
2379
- updateConfig({
2380
- ...config,
2381
- yAxis: {
2382
- ...config.yAxis,
2383
- anchors: copiedAnchors
2384
- }
2385
- })
2386
- }}
2387
- >
2388
- <option>Select</option>
2389
- {lineOptions.map(line => (
2390
- <option key={line.key}>{line.value}</option>
2391
- ))}
2392
- </select>
2393
- </label>
2394
- </AccordionItemPanel>
2395
- </AccordionItem>
2396
- ))}
2397
- </Accordion>
2398
-
2399
- <button
2400
- className='btn full-width'
2401
- onClick={e => {
2402
- e.preventDefault()
2403
- const anchors = [...config.yAxis.anchors]
2404
- anchors.push({})
2405
- updateConfig({
2406
- ...config,
2407
- yAxis: {
2408
- ...config.yAxis,
2409
- anchors
2410
- }
2411
- })
2412
- }}
2413
- >
2414
- Add Anchor
2415
- </button>
2416
- </div>
2417
- )}
2418
- </AccordionItemPanel>
2419
- </AccordionItem>
2420
- {visSupportsRegions() && (
2421
- <AccordionItem>
2422
- <AccordionItemHeading>
2423
- <AccordionItemButton>Regions</AccordionItemButton>
2424
- </AccordionItemHeading>
2425
- <AccordionItemPanel>
2426
- <Regions config={config} updateConfig={updateConfig} />
2425
+ <button
2426
+ className='btn full-width'
2427
+ onClick={e => {
2428
+ e.preventDefault()
2429
+ const anchors = [...config.yAxis.anchors]
2430
+ anchors.push({} as Anchor)
2431
+ updateConfig({
2432
+ ...config,
2433
+ yAxis: {
2434
+ ...config.yAxis,
2435
+ anchors
2436
+ }
2437
+ })
2438
+ }}
2439
+ >
2440
+ Add Anchor
2441
+ </button>
2442
+ </div>
2443
+ )}
2427
2444
  </AccordionItemPanel>
2428
2445
  </AccordionItem>
2429
- )}{' '}
2446
+ )}
2447
+ <Panels.Regions name='Regions' />
2430
2448
  {/* Columns */}
2431
- {config.visualizationType !== 'Box Plot' && config.table.showVertical && (
2449
+ {config.visualizationType !== 'Box Plot' && (
2432
2450
  <AccordionItem>
2433
2451
  <AccordionItemHeading>
2434
2452
  <AccordionItemButton>Columns</AccordionItemButton>
@@ -2463,12 +2481,28 @@ const EditorPanel = () => {
2463
2481
  <label>
2464
2482
  <span className='edit-label column-heading'>Column</span>
2465
2483
  <select
2466
- value={config.columns[val] ? config.columns[val].name : columnsOptions[0]}
2484
+ value={config.columns[val] ? config.columns[val].name : getColumns()[0]}
2467
2485
  onChange={event => {
2468
2486
  editColumn(val, 'name', event.target.value)
2469
2487
  }}
2470
2488
  >
2471
- {columnsOptions}
2489
+ {getColumns().map(option => (
2490
+ <option>{option}</option>
2491
+ ))}
2492
+ </select>
2493
+ </label>
2494
+ <label>
2495
+ <span className='edit-label column-heading'>Associate to Series</span>
2496
+ <select
2497
+ value={config.columns[val] ? config.columns[val].series : ''}
2498
+ onChange={event => {
2499
+ editColumn(val, 'series', event.target.value)
2500
+ }}
2501
+ >
2502
+ <option value=''>Select series</option>
2503
+ {config.series.map(series => (
2504
+ <option>{series.dataKey}</option>
2505
+ ))}
2472
2506
  </select>
2473
2507
  </label>
2474
2508
  <TextField value={config.columns[val].label} section='columns' subsection={val} fieldName='label' label='Label' updateField={updateField} />
@@ -2491,32 +2525,33 @@ const EditorPanel = () => {
2491
2525
  </label>
2492
2526
  </li>
2493
2527
  <li>
2494
- <label className='checkbox'>
2495
- <input
2496
- type='checkbox'
2497
- checked={config.columns[val].dataTable}
2498
- onChange={event => {
2499
- editColumn(val, 'dataTable', event.target.checked)
2500
- }}
2501
- />
2502
- <span className='edit-label'>Show in Data Table</span>
2503
- </label>
2528
+ {config.table.showVertical && (
2529
+ <label className='checkbox'>
2530
+ <input
2531
+ type='checkbox'
2532
+ checked={config.columns[val].dataTable}
2533
+ onChange={event => {
2534
+ editColumn(val, 'dataTable', event.target.checked)
2535
+ }}
2536
+ />
2537
+ <span className='edit-label'>Show in Data Table</span>
2538
+ </label>
2539
+ )}
2504
2540
  </li>
2505
2541
  {/* disable for now */}
2506
- {/*
2542
+
2507
2543
  <li>
2508
2544
  <label className='checkbox'>
2509
2545
  <input
2510
2546
  type='checkbox'
2511
- checked={config.columns[val].tooltip}
2547
+ checked={config.columns[val].tooltips || false}
2512
2548
  onChange={event => {
2513
- editColumn(val, 'tooltip', event.target.checked)
2549
+ updateSeriesTooltip(val, event.target.checked)
2514
2550
  }}
2515
2551
  />
2516
- <span className='edit-label'>Display in Tooltips</span>
2552
+ <span className='edit-label'>Show in tooltip</span>
2517
2553
  </label>
2518
2554
  </li>
2519
- */}
2520
2555
 
2521
2556
  {config.visualizationType === 'Forest Plot' && (
2522
2557
  <>
@@ -2532,18 +2567,6 @@ const EditorPanel = () => {
2532
2567
  <span className='edit-label'>Show in Forest Plot</span>
2533
2568
  </label>
2534
2569
  </li>
2535
- <li>
2536
- <label className='checkbox'>
2537
- <input
2538
- type='checkbox'
2539
- checked={config.columns[val].tooltips || false}
2540
- onChange={event => {
2541
- updateSeriesTooltip(val, event.target.checked)
2542
- }}
2543
- />
2544
- <span className='edit-label'>Show in tooltip</span>
2545
- </label>
2546
- </li>
2547
2570
  <li>
2548
2571
  <label className='checkbox'>
2549
2572
  <input
@@ -2616,20 +2639,18 @@ const EditorPanel = () => {
2616
2639
  >
2617
2640
  Remove
2618
2641
  </button>
2619
- <label>
2620
- <span className='edit-label column-heading'>Category</span>
2621
- <TextField
2622
- value={val}
2623
- section='legend'
2624
- subsection={null}
2625
- fieldName='additionalCategories'
2626
- updateField={(section, subsection, fieldName, value) => {
2627
- const updatedAdditionaCategories = [...config.legend.additionalCategories]
2628
- updatedAdditionaCategories[i] = value
2629
- updateField(section, subsection, fieldName, updatedAdditionaCategories)
2630
- }}
2631
- />
2632
- </label>
2642
+ <TextField
2643
+ value={val}
2644
+ label='Category'
2645
+ section='legend'
2646
+ subsection={null}
2647
+ fieldName='additionalCategories'
2648
+ updateField={(section, subsection, fieldName, value) => {
2649
+ const updatedAdditionaCategories = [...config.legend.additionalCategories]
2650
+ updatedAdditionaCategories[i] = value
2651
+ updateField(section, subsection, fieldName, updatedAdditionaCategories)
2652
+ }}
2653
+ />
2633
2654
  </fieldset>
2634
2655
  ))}
2635
2656
  <button
@@ -2684,22 +2705,18 @@ const EditorPanel = () => {
2684
2705
  </Tooltip>
2685
2706
  }
2686
2707
  />
2687
-
2688
2708
  {/* {config.visualizationType === 'Box Plot' &&
2689
2709
  <>
2690
2710
  <CheckBox value={config.boxplot.legend.displayHowToReadText} fieldName='displayHowToReadText' section='boxplot' subsection='legend' label='Display How To Read Text' updateField={updateField} />
2691
2711
  <TextField type='textarea' value={config.boxplot.legend.howToReadText} updateField={updateField} fieldName='howToReadText' section='boxplot' subsection='legend' label='How to read text' />
2692
2712
  </>
2693
2713
  } */}
2694
-
2695
- {config.visualizationType !== 'Box Plot' && <CheckBox value={config.legend.showLegendValuesTooltip ? true : false} section='legend' fieldName='showLegendValuesTooltip' label='Show Legend Values in Tooltip' updateField={updateField} />}
2696
-
2697
2714
  {config.visualizationType === 'Line' && <CheckBox value={config.legend.lineMode} section='legend' fieldName='lineMode' label='Show Lined Style Legend' updateField={updateField} />}
2698
-
2699
2715
  {config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1 && (
2700
2716
  <Select value={config.legend.colorCode} section='legend' fieldName='colorCode' label='Color code by category' initial='Select' updateField={updateField} options={getDataValueOptions(data)} />
2701
2717
  )}
2702
2718
  <Select value={config.legend.behavior} section='legend' fieldName='behavior' label='Legend Behavior (When clicked)' updateField={updateField} options={['highlight', 'isolate']} />
2719
+ {config.legend.behavior === 'highlight' && config.tooltips.singleSeries && <CheckBox value={config.legend.highlightOnHover} section='legend' fieldName='highlightOnHover' label='HIGHLIGHT DATA SERIES ON HOVER' updateField={updateField} />}
2703
2720
  <TextField value={config.legend.label} section='legend' fieldName='label' label='Title' updateField={updateField} />
2704
2721
  <Select value={config.legend.position} section='legend' fieldName='position' label='Position' updateField={updateField} options={['right', 'left', 'bottom']} />
2705
2722
  {config.legend.position === 'bottom' && (
@@ -2768,7 +2785,7 @@ const EditorPanel = () => {
2768
2785
  }}
2769
2786
  >
2770
2787
  <option value=''>- Select Option -</option>
2771
- {getFilters(true).map((dataKey, index) => (
2788
+ {getFilters().map((dataKey, index) => (
2772
2789
  <option value={dataKey} key={index}>
2773
2790
  {dataKey}
2774
2791
  </option>
@@ -2796,8 +2813,12 @@ const EditorPanel = () => {
2796
2813
  updateFilterProp('filterStyle', index, e.target.value)
2797
2814
  }}
2798
2815
  >
2799
- {filterStyleOptions.map(item => {
2800
- return <option value={item}>{item}</option>
2816
+ {filterStyleOptions.map((item, index) => {
2817
+ return (
2818
+ <option key={`filter-style-${index}`} value={item}>
2819
+ {item}
2820
+ </option>
2821
+ )
2801
2822
  })}
2802
2823
  </select>
2803
2824
  </label>
@@ -2834,7 +2855,7 @@ const EditorPanel = () => {
2834
2855
  <Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
2835
2856
  {(provided, snapshot) => (
2836
2857
  <li>
2837
- <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
2858
+ <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
2838
2859
  {value}
2839
2860
  </div>
2840
2861
  </li>
@@ -2906,7 +2927,10 @@ const EditorPanel = () => {
2906
2927
  {/*<CheckBox value={config.animateReplay} fieldName="animateReplay" label="Replay Animation When Filters Are Changed" updateField={updateField} />*/}
2907
2928
 
2908
2929
  {((config.series?.some(series => series.type === 'Line' || series.type === 'dashed-lg' || series.type === 'dashed-sm' || series.type === 'dashed-md') && config.visualizationType === 'Combo') || config.visualizationType === 'Line') && (
2909
- <Select value={config.lineDatapointStyle} fieldName='lineDatapointStyle' label='Line Datapoint Style' updateField={updateField} options={['hidden', 'hover', 'always show']} />
2930
+ <>
2931
+ <Select value={config.lineDatapointStyle} fieldName='lineDatapointStyle' label='Line Datapoint Style' updateField={updateField} options={['hidden', 'hover', 'always show']} />
2932
+ <Select value={config.lineDatapointColor} fieldName='lineDatapointColor' label='Line Datapoint Color' updateField={updateField} options={['Same as Line', 'Lighter than Line']} />
2933
+ </>
2910
2934
  )}
2911
2935
 
2912
2936
  {/* eslint-disable */}
@@ -3061,9 +3085,9 @@ const EditorPanel = () => {
3061
3085
  />
3062
3086
  </>
3063
3087
  )}
3064
- {visSupportsBarThickness() && config.orientation === 'horizontal' && !config.isLollipopChart && config.yAxis.labelPlacement !== 'On Bar' && <TextField type='number' value={config.barHeight || '25'} fieldName='barHeight' label=' Bar Thickness' updateField={updateField} min='15' />}
3088
+ {visSupportsBarThickness() && config.orientation === 'horizontal' && !config.isLollipopChart && config.yAxis.labelPlacement !== 'On Bar' && <TextField type='number' value={config.barHeight || '25'} fieldName='barHeight' label=' Bar Thickness' updateField={updateField} min={15} />}
3065
3089
  {((config.visualizationType === 'Bar' && config.orientation !== 'horizontal') || config.visualizationType === 'Combo') && <TextField value={config.barThickness} type='number' fieldName='barThickness' label='Bar Thickness' updateField={updateField} />}
3066
- {visSupportsBarSpace() && <TextField type='number' value={config.barSpace || '15'} fieldName='barSpace' label='Bar Space' updateField={updateField} min='0' />}
3090
+ {visSupportsBarSpace() && <TextField type='number' value={config.barSpace || '15'} fieldName='barSpace' label='Bar Space' updateField={updateField} min={0} />}
3067
3091
  {(config.visualizationType === 'Bar' || config.visualizationType === 'Line' || config.visualizationType === 'Combo') && <CheckBox value={config.topAxis.hasLine} section='topAxis' fieldName='hasLine' label='Add Top Axis Line' updateField={updateField} />}
3068
3092
 
3069
3093
  {config.visualizationType === 'Spark Line' && (
@@ -3105,6 +3129,7 @@ const EditorPanel = () => {
3105
3129
  />
3106
3130
  </label>
3107
3131
  )}
3132
+ {config.visualizationType === 'Bar' && <CheckBox value={config.tooltips.singleSeries} fieldName='singleSeries' section='tooltips' label='SHOW HOVER FOR SINGLE DATA SERIES' updateField={updateField} />}
3108
3133
 
3109
3134
  <label>
3110
3135
  <span className='edit-label column-heading'>No Data Message</span>
@@ -3131,94 +3156,11 @@ const EditorPanel = () => {
3131
3156
  <AccordionItemButton>Data Table</AccordionItemButton>
3132
3157
  </AccordionItemHeading>
3133
3158
  <AccordionItemPanel>
3134
- <TextField
3135
- value={config.table.label}
3136
- updateField={updateField}
3137
- section='table'
3138
- fieldName='label'
3139
- id='tableLabel'
3140
- label='Data Table Title'
3141
- placeholder='Data Table'
3142
- tooltip={
3143
- <Tooltip style={{ textTransform: 'none' }}>
3144
- <Tooltip.Target>
3145
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3146
- </Tooltip.Target>
3147
- <Tooltip.Content>
3148
- <p>Label is required for Data Table for 508 Compliance</p>
3149
- </Tooltip.Content>
3150
- </Tooltip>
3151
- }
3152
- />
3153
- <CheckBox
3154
- value={config.table.show}
3155
- section='table'
3156
- fieldName='show'
3157
- label='Show Data Table'
3158
- updateField={updateField}
3159
- className='column-heading'
3160
- tooltip={
3161
- <Tooltip style={{ textTransform: 'none' }}>
3162
- <Tooltip.Target>
3163
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
3164
- </Tooltip.Target>
3165
- <Tooltip.Content>
3166
- <p>Hiding the data table may affect accessibility. An alternate form of accessing visualization data is a 508 requirement.</p>
3167
- </Tooltip.Content>
3168
- </Tooltip>
3169
- }
3170
- />
3171
- {config.visualizationType !== 'Box Plot' && (
3172
- <CheckBox
3173
- value={config.table.showVertical}
3174
- section='table'
3175
- fieldName='showVertical'
3176
- label='Show Vertical Data'
3177
- updateField={updateField}
3178
- className='column-heading'
3179
- tooltip={
3180
- <Tooltip style={{ textTransform: 'none' }}>
3181
- <Tooltip.Target>
3182
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
3183
- </Tooltip.Target>
3184
- <Tooltip.Content>
3185
- <p>This will draw the data table with vertical data instead of horizontal.</p>
3186
- </Tooltip.Content>
3187
- </Tooltip>
3188
- }
3189
- />
3190
- )}
3191
- <TextField value={config.table.indexLabel} section='table' fieldName='indexLabel' label='Index Column Header' updateField={updateField} />
3192
- <TextField
3193
- value={config.table.caption}
3194
- updateField={updateField}
3195
- section='table'
3196
- type='textarea'
3197
- fieldName='caption'
3198
- label='Data Table Caption'
3199
- placeholder=' Data table'
3200
- tooltip={
3201
- <Tooltip style={{ textTransform: 'none' }}>
3202
- <Tooltip.Target>
3203
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3204
- </Tooltip.Target>
3205
- <Tooltip.Content>
3206
- <p>Enter a description of the data table to be read by screen readers.</p>
3207
- </Tooltip.Content>
3208
- </Tooltip>
3209
- }
3210
- />
3211
- <CheckBox value={config.table.limitHeight} section='table' fieldName='limitHeight' label='Limit Table Height' updateField={updateField} />
3212
- {config.table.limitHeight && <TextField value={config.table.height} section='table' fieldName='height' label='Data Table Height' type='number' min='0' max='500' placeholder='Height(px)' updateField={updateField} />}
3213
- <CheckBox value={config.table.expanded} section='table' fieldName='expanded' label='Expanded by Default' updateField={updateField} />
3214
- {isDashboard && <CheckBox value={config.table.showDataTableLink} section='table' fieldName='showDataTableLink' label='Show Data Table Name & Link' updateField={updateField} />}
3215
- {isLoadedFromUrl && <CheckBox value={config.table.showDownloadUrl} section='table' fieldName='showDownloadUrl' label='Show URL to Automatically Updated Data' updateField={updateField} />}
3216
- <CheckBox value={config.table.download} section='table' fieldName='download' label='Show Download CSV Link' updateField={updateField} />
3217
- <CheckBox value={config.table.showDownloadImgButton} section='table' fieldName='showDownloadImgButton' label='Display Image Button' updateField={updateField} />
3218
- {/* <CheckBox value={config.table.showDownloadPdfButton} section='table' fieldName='showDownloadPdfButton' label='Display PDF Button' updateField={updateField} /> */}
3159
+ <DataTableEditor config={config} columns={Object.keys(data[0] || {})} updateField={updateField} isDashboard={isDashboard} isLoadedFromUrl={isLoadedFromUrl} />{' '}
3219
3160
  </AccordionItemPanel>
3220
3161
  </AccordionItem>
3221
3162
  )}
3163
+ {/* {(config.visualizationType === 'Bar' || config.visualizationType === 'Line') && <Panels.DateHighlighting name='Date Highlighting' />} */}
3222
3164
  </Accordion>
3223
3165
  {config.type !== 'Spark Line' && <AdvancedEditor loadConfig={updateConfig} state={config} convertStateToConfig={convertStateToConfig} />}
3224
3166
  </section>