@cdc/chart 4.23.11 → 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 (103) hide show
  1. package/dist/cdcchart.js +30220 -29764
  2. package/examples/feature/bar/additional-column-tooltip.json +446 -0
  3. package/examples/feature/bar/tall-data.json +98 -0
  4. package/examples/feature/forest-plot/forest-plot.json +63 -19
  5. package/examples/feature/forest-plot/linear.json +52 -3
  6. package/examples/feature/forest-plot/log.json +26 -0
  7. package/examples/feature/forest-plot/logarithmic.json +0 -35
  8. package/examples/feature/line/line-chart-preliminary.json +346 -0
  9. package/examples/feature/scatterplot/scatterplot.json +272 -33
  10. package/examples/private/chart-t.json +3740 -0
  11. package/examples/private/combo.json +369 -0
  12. package/examples/private/epi-data.csv +13 -0
  13. package/examples/private/epi-data.json +62 -0
  14. package/examples/private/epi.json +403 -0
  15. package/examples/private/occupancy.json +109283 -0
  16. package/examples/private/prod-line-config.json +401 -0
  17. package/examples/private/region-data.json +822 -0
  18. package/examples/private/region-testing.json +312 -0
  19. package/examples/private/scaling.json +45325 -0
  20. package/examples/private/testing-data.json +1739 -0
  21. package/examples/private/testing.json +816 -0
  22. package/index.html +7 -7
  23. package/package.json +2 -2
  24. package/src/CdcChart.tsx +29 -210
  25. package/src/ConfigContext.tsx +6 -0
  26. package/src/_stories/ChartEditor.stories.tsx +22 -0
  27. package/src/_stories/ChartLine.preliminary.tsx +19 -0
  28. package/src/_stories/_mock/pie_config.json +191 -0
  29. package/src/_stories/_mock/pie_data.json +218 -0
  30. package/src/_stories/_mock/preliminary_mock.json +346 -0
  31. package/src/components/{AreaChart.Stacked.jsx → AreaChart/components/AreaChart.Stacked.jsx} +2 -2
  32. package/src/components/{AreaChart.jsx → AreaChart/components/AreaChart.jsx} +1 -1
  33. package/src/components/AreaChart/index.tsx +4 -0
  34. package/src/components/{BarChart.Horizontal.tsx → BarChart/components/BarChart.Horizontal.tsx} +8 -8
  35. package/src/components/{BarChart.StackedHorizontal.tsx → BarChart/components/BarChart.StackedHorizontal.tsx} +37 -7
  36. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +106 -0
  37. package/src/components/{BarChart.Vertical.tsx → BarChart/components/BarChart.Vertical.tsx} +41 -57
  38. package/src/components/BarChart/components/BarChart.jsx +39 -0
  39. package/src/components/{BarChartType.jsx → BarChart/components/BarChartType.jsx} +0 -2
  40. package/src/components/BarChart/components/context.tsx +13 -0
  41. package/src/components/BarChart/index.tsx +3 -0
  42. package/src/components/{BoxPlot.jsx → BoxPlot/BoxPlot.jsx} +1 -1
  43. package/src/components/BoxPlot/index.tsx +3 -0
  44. package/src/components/{EditorPanel.jsx → EditorPanel/EditorPanel.tsx} +667 -851
  45. package/src/components/EditorPanel/components/Panel.DateHighlighting.tsx +109 -0
  46. package/src/components/{ForestPlotSettings.jsx → EditorPanel/components/Panel.ForestPlotSettings.tsx} +87 -166
  47. package/src/components/EditorPanel/components/Panel.Regions.tsx +168 -0
  48. package/src/components/{Series.jsx → EditorPanel/components/Panel.Series.tsx} +1 -1
  49. package/src/components/EditorPanel/components/PanelProps.ts +3 -0
  50. package/src/components/EditorPanel/components/Panels.tsx +13 -0
  51. package/src/components/EditorPanel/components/panels.scss +72 -0
  52. package/src/components/EditorPanel/editor-panel.scss +751 -0
  53. package/src/components/EditorPanel/index.tsx +3 -0
  54. package/src/{hooks → components/EditorPanel}/useEditorPermissions.js +29 -2
  55. package/src/components/{Forecasting.jsx → Forecasting/Forecasting.jsx} +1 -1
  56. package/src/components/Forecasting/index.tsx +3 -0
  57. package/src/components/ForestPlot/ForestPlot.tsx +254 -0
  58. package/src/components/ForestPlot/ForestPlotProps.ts +7 -0
  59. package/src/components/ForestPlot/index.tsx +1 -209
  60. package/src/components/{Legend.jsx → Legend/Legend.tsx} +150 -113
  61. package/src/components/Legend/index.tsx +3 -0
  62. package/src/components/LineChart/LineChartProps.ts +29 -0
  63. package/src/components/LineChart/{LineChart.Circle.tsx → components/LineChart.Circle.tsx} +12 -3
  64. package/src/components/LineChart/helpers.ts +45 -0
  65. package/src/components/LineChart/index.tsx +20 -8
  66. package/src/components/LinearChart.jsx +52 -69
  67. package/src/components/{PieChart.jsx → PieChart/PieChart.tsx} +16 -7
  68. package/src/components/PieChart/index.tsx +3 -0
  69. package/src/components/Regions/components/Regions.tsx +135 -0
  70. package/src/components/Regions/index.tsx +3 -0
  71. package/src/components/{ScatterPlot.jsx → ScatterPlot/ScatterPlot.jsx} +3 -3
  72. package/src/components/ScatterPlot/index.tsx +3 -0
  73. package/src/components/{SparkLine.jsx → Sparkline/SparkLine.jsx} +2 -2
  74. package/src/components/Sparkline/index.tsx +3 -0
  75. package/src/data/initial-state.js +5 -6
  76. package/src/helpers/abbreviateNumber.ts +17 -0
  77. package/src/helpers/computeMarginBottom.ts +55 -0
  78. package/src/helpers/filterData.ts +18 -0
  79. package/src/helpers/generateColorsArray.ts +8 -0
  80. package/src/helpers/getQuartiles.ts +30 -0
  81. package/src/helpers/handleChartAriaLabels.ts +19 -0
  82. package/src/helpers/handleLineType.ts +18 -0
  83. package/src/helpers/lineOptions.ts +18 -0
  84. package/src/helpers/sort.ts +7 -0
  85. package/src/helpers/tests/computeMarginBottom.test.ts +20 -0
  86. package/src/hooks/useBarChart.js +7 -6
  87. package/src/hooks/useScales.ts +1 -1
  88. package/src/hooks/{useTooltip.jsx → useTooltip.tsx} +23 -21
  89. package/src/scss/main.scss +67 -3
  90. package/src/types/ChartConfig.ts +158 -23
  91. package/src/types/ChartContext.ts +26 -10
  92. package/src/types/ForestPlot.ts +7 -14
  93. package/examples/feature/scatterplot/scatterplot-continuous.csv +0 -17
  94. package/src/ConfigContext.jsx +0 -5
  95. package/src/components/BarChart.StackedVertical.tsx +0 -91
  96. package/src/components/BarChart.jsx +0 -30
  97. package/src/components/ForestPlot/Readme.md +0 -0
  98. package/src/scss/LinearChart.scss +0 -0
  99. package/src/scss/editor-panel.scss +0 -745
  100. package/src/scss/legend.scss +0 -206
  101. package/src/scss/mixins.scss +0 -0
  102. package/src/scss/variables.scss +0 -1
  103. package/src/types/ChartProps.ts +0 -7
@@ -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,128 +10,31 @@ 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
- import useMinMax from './../hooks/useMinMax'
30
-
31
- /* eslint-disable react-hooks/rules-of-hooks */
32
- const TextField = memo(({ label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = 'input', i = null, min = null, ...attributes }) => {
33
- const [value, setValue] = useState(stateValue)
34
-
35
- const [debouncedValue] = useDebounce(value, 500)
36
-
37
- useEffect(() => {
38
- if ('string' === typeof debouncedValue && stateValue !== debouncedValue) {
39
- updateField(section, subsection, fieldName, debouncedValue, i)
40
- }
41
- }, [debouncedValue]) // eslint-disable-line
42
-
43
- let name = subsection ? `${section}-${subsection}-${fieldName}` : `${section}-${subsection}-${fieldName}`
44
-
45
- const onChange = e => {
46
- if ('number' !== type || min === null) {
47
- setValue(e.target.value)
48
- } else {
49
- if (!e.target.value || min <= parseFloat(e.target.value)) {
50
- setValue(e.target.value)
51
- } else {
52
- setValue(min.toString())
53
- }
54
- }
55
- }
56
-
57
- let formElement = <input type='text' name={name} onChange={onChange} {...attributes} value={value} />
58
-
59
- if ('textarea' === type) {
60
- formElement = <textarea name={name} onChange={onChange} {...attributes} value={value}></textarea>
61
- }
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'
62
29
 
63
- if ('number' === type) {
64
- formElement = <input type='number' name={name} onChange={onChange} {...attributes} value={value} />
65
- }
66
-
67
- if ('date' === type) {
68
- formElement = <input type='date' name={name} onChange={onChange} {...attributes} value={value} />
69
- }
70
-
71
- return (
72
- <label>
73
- <span className='edit-label column-heading'>
74
- {label}
75
- {tooltip}
76
- </span>
77
- {formElement}
78
- </label>
79
- )
80
- })
81
-
82
- const CheckBox = memo(({ label, value, fieldName, section = null, subsection = null, tooltip, updateField, ...attributes }) => (
83
- <label className='checkbox column-heading'>
84
- <input
85
- type='checkbox'
86
- name={fieldName}
87
- checked={value}
88
- onChange={e => {
89
- updateField(section, subsection, fieldName, !value)
90
- }}
91
- {...attributes}
92
- />
93
- <span className='edit-label'>
94
- {label}
95
- {tooltip}
96
- </span>
97
- </label>
98
- ))
99
-
100
- const Select = memo(({ label, value, options, fieldName, section = null, subsection = null, required = false, tooltip, updateField, initial: initialValue, ...attributes }) => {
101
- let optionsJsx = options.map((optionName, index) => (
102
- <option value={optionName} key={index}>
103
- {optionName}
104
- </option>
105
- ))
106
-
107
- if (initialValue) {
108
- optionsJsx.unshift(
109
- <option value='' key='initial'>
110
- {initialValue}
111
- </option>
112
- )
113
- }
30
+ import { type ChartConfig } from '../../types/ChartConfig'
31
+ import { type ChartContext } from '../../types/ChartContext'
114
32
 
115
- return (
116
- <label>
117
- <span className='edit-label'>
118
- {label}
119
- {tooltip}
120
- </span>
121
- <select
122
- className={required && !value ? 'warning' : ''}
123
- name={fieldName}
124
- value={value}
125
- onChange={event => {
126
- updateField(section, subsection, fieldName, event.target.value)
127
- }}
128
- {...attributes}
129
- >
130
- {optionsJsx}
131
- </select>
132
- </label>
133
- )
134
- })
33
+ import './editor-panel.scss'
34
+ import { Anchor } from '@cdc/core/types/Axis'
35
+ import DataTableEditor from '@cdc/core/components/EditorPanel/DataTableEditor'
135
36
 
136
- const DataSuppression = memo(({ config, updateConfig, data }) => {
37
+ const DataSuppression = memo(({ config, updateConfig, data }: any) => {
137
38
  const getColumnOptions = () => {
138
39
  const keys = new Set()
139
40
  data.forEach(d => {
@@ -207,104 +108,99 @@ const DataSuppression = memo(({ config, updateConfig, data }) => {
207
108
  </>
208
109
  )
209
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
+ }
210
121
 
211
- const Regions = memo(({ config, updateConfig }) => {
212
- let regionUpdate = (fieldName, value, i) => {
213
- let regions = []
214
-
215
- if (config.regions) {
216
- regions = [...config.regions]
122
+ const getTypeOptions = () => {
123
+ if (config.visualizationType === 'Line' || config.visualizationType === 'Combo') {
124
+ return ['effect']
125
+ } else {
126
+ return ['suppression']
217
127
  }
218
-
219
- regions[i][fieldName] = value
220
- updateConfig({ ...config, regions })
221
128
  }
222
129
 
223
- // only for Regions
224
- 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
+ }
225
138
 
226
139
  let removeColumn = i => {
227
- let regions = []
140
+ let preliminaryData = []
228
141
 
229
- if (config.regions) {
230
- regions = [...config.regions]
142
+ if (config.preliminaryData) {
143
+ preliminaryData = [...config.preliminaryData]
231
144
  }
232
145
 
233
- regions.splice(i, 1)
146
+ preliminaryData.splice(i, 1)
234
147
 
235
- updateConfig({ ...config, regions })
148
+ updateConfig({ ...config, preliminaryData })
236
149
  }
237
150
 
238
151
  let addColumn = () => {
239
- let regions = []
152
+ let preliminaryData = config.preliminaryData ? [...config.preliminaryData] : []
153
+ preliminaryData.push({ type: '', label: '', column: '', value: '', style: '' })
154
+ updateConfig({ ...config, preliminaryData })
155
+ }
240
156
 
241
- if (config.regions) {
242
- regions = [...config.regions]
243
- }
157
+ let update = (fieldName, value, i) => {
158
+ let preliminaryData = []
244
159
 
245
- regions.push({})
160
+ if (config.preliminaryData) {
161
+ preliminaryData = [...config.preliminaryData]
162
+ }
246
163
 
247
- updateConfig({ ...config, regions })
164
+ preliminaryData[i][fieldName] = value
165
+ updateConfig({ ...config, preliminaryData })
248
166
  }
249
167
 
250
168
  return (
251
169
  <>
252
- {config.regions &&
253
- config.regions.map(({ label, color, from, to, background }, i) => (
254
- <div className='edit-block' key={`region-${i}`}>
255
- <button
256
- type='button'
257
- className='remove-column'
258
- onClick={event => {
259
- event.preventDefault()
260
- removeColumn(i)
261
- }}
262
- >
263
- Remove
264
- </button>
265
- <TextField value={label} label='Region Label' fieldName='label' i={i} updateField={updateField} />
266
- <div className='two-col-inputs'>
267
- <TextField value={color} label='Text Color' fieldName='color' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
268
- <TextField value={background} label='Background' fieldName='background' updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)} />
269
- </div>
270
- <div className='two-col-inputs'>
271
- <TextField
272
- value={from}
273
- label='From Value'
274
- fieldName='from'
275
- updateField={(section, subsection, fieldName, value) => regionUpdate(fieldName, value, i)}
276
- tooltip={
277
- <Tooltip style={{ textTransform: 'none' }}>
278
- <Tooltip.Target>
279
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
280
- </Tooltip.Target>
281
- <Tooltip.Content>
282
- <p>The date needs to be in the original format of the data. Not the displayed format of the data.</p>
283
- </Tooltip.Content>
284
- </Tooltip>
285
- }
286
- />
287
- <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)} />
288
191
  </div>
289
- </div>
290
- ))}
291
- {!config.regions && <p style={{ textAlign: 'center' }}>There are currently no regions.</p>}
292
- <button
293
- type='button'
294
- className='btn full-width'
295
- onClick={e => {
296
- e.preventDefault()
297
- addColumn()
298
- }}
299
- >
300
- 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'}
301
197
  </button>
302
198
  </>
303
199
  )
304
200
  })
305
201
 
306
202
  const EditorPanel = () => {
307
- 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)
308
204
 
309
205
  const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
310
206
 
@@ -328,6 +224,9 @@ const EditorPanel = () => {
328
224
  visCanAnimate,
329
225
  visHasLegend,
330
226
  visHasBrushChart,
227
+ visSupportsDateCategoryAxis,
228
+ visSupportsValueAxisMin,
229
+ visSupportsValueAxisMax,
331
230
  visSupportsDateCategoryAxisLabel,
332
231
  visSupportsDateCategoryAxisLine,
333
232
  visSupportsDateCategoryAxisTicks,
@@ -884,7 +783,7 @@ const EditorPanel = () => {
884
783
  }
885
784
 
886
785
  const validateMinValue = () => {
887
- const enteredValue = config[section].min
786
+ const enteredValue = parseFloat(config[section].min)
888
787
  let minVal = Number(minValue)
889
788
  let message = ''
890
789
 
@@ -892,19 +791,19 @@ const EditorPanel = () => {
892
791
  case config.useLogScale && ['Line', 'Combo', 'Bar'].includes(config.visualizationType) && enteredValue < 0:
893
792
  message = 'Negative numbers are not supported in logarithmic scale'
894
793
  break
895
- case (config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && enteredValue && parseFloat(enteredValue) > minVal:
794
+ case (config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && enteredValue > minVal:
896
795
  message = 'Value should not exceed ' + minValue
897
796
  break
898
- case config.visualizationType === 'Combo' && isAllLine && enteredValue && parseFloat(enteredValue) > minVal:
797
+ case config.visualizationType === 'Combo' && isAllLine && enteredValue > minVal:
899
798
  message = 'Value should not exceed ' + minValue
900
799
  break
901
- 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:
902
801
  message = config.useLogScale ? 'Value must be equal to 0' : 'Value must be less than or equal to 0'
903
802
  break
904
- 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):
905
804
  message = 'Value must be less than ' + Math.min(minVal, config.xAxis.target)
906
805
  break
907
- case config.visualizationType !== 'Deviation Bar' && enteredValue && minVal < 0 && parseFloat(enteredValue) > minVal:
806
+ case config.visualizationType !== 'Deviation Bar' && enteredValue && minVal < 0 && enteredValue > minVal:
908
807
  message = 'Value should not exceed ' + minValue
909
808
  break
910
809
  default:
@@ -1116,7 +1015,7 @@ const EditorPanel = () => {
1116
1015
  {undefined === config.newViz && config.runtime && config.runtime.editorErrorMessage && <Error />}
1117
1016
  <button className={displayPanel ? `editor-toggle` : `editor-toggle collapsed`} title={displayPanel ? `Collapse Editor` : `Expand Editor`} onClick={onBackClick}></button>
1118
1017
  <section className={`${displayPanel ? 'editor-panel cove' : 'hidden editor-panel cove'}${isDashboard ? ' dashboard' : ''}`}>
1119
- <div aria-level='2' role='heading' className='heading-2'>
1018
+ <div aria-level={2} role='heading' className='heading-2'>
1120
1019
  Configure Chart
1121
1020
  </div>
1122
1021
  <section className='form-container'>
@@ -1251,7 +1150,7 @@ const EditorPanel = () => {
1251
1150
  {visSupportsChartHeight() && config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
1252
1151
  </AccordionItemPanel>
1253
1152
  </AccordionItem>
1254
- {config.visualizationType === 'Forest Plot' && <ForestPlotSettings />}
1153
+ {config.visualizationType === 'Forest Plot' && <Panels.ForestPlot name='Forest Plot Settings' editColumn={editColumn} setCategoryAxis={setCategoryAxis} />}
1255
1154
  {config.visualizationType !== 'Pie' && config.visualizationType !== 'Forest Plot' && (
1256
1155
  <AccordionItem>
1257
1156
  <AccordionItemHeading>
@@ -1274,7 +1173,7 @@ const EditorPanel = () => {
1274
1173
  options={getColumns()}
1275
1174
  />
1276
1175
  {config.series && config.series.length !== 0 && (
1277
- <Series.Wrapper getColumns={getColumns}>
1176
+ <Panels.Series.Wrapper getColumns={getColumns}>
1278
1177
  <fieldset>
1279
1178
  <legend className='edit-label float-left'>Displaying</legend>
1280
1179
  <Tooltip style={{ textTransform: 'none' }}>
@@ -1293,14 +1192,14 @@ const EditorPanel = () => {
1293
1192
  {provided => {
1294
1193
  return (
1295
1194
  <ul {...provided.droppableProps} className='series-list' ref={provided.innerRef}>
1296
- <Series.List series={config.series} getItemStyle={getItemStyle} sortableItemStyles={sortableItemStyles} chartsWithOptions={chartsWithOptions} />
1195
+ <Panels.Series.List series={config.series} getItemStyle={getItemStyle} sortableItemStyles={sortableItemStyles} chartsWithOptions={chartsWithOptions} />
1297
1196
  {provided.placeholder}
1298
1197
  </ul>
1299
1198
  )
1300
1199
  }}
1301
1200
  </Droppable>
1302
1201
  </DragDropContext>
1303
- </Series.Wrapper>
1202
+ </Panels.Series.Wrapper>
1304
1203
  )}
1305
1204
  </>
1306
1205
  {config.series && config.series.length <= 1 && config.visualizationType === 'Bar' && (
@@ -1312,6 +1211,7 @@ const EditorPanel = () => {
1312
1211
  )}
1313
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']} />}
1314
1213
  {/* {visHasDataSuppression() && <DataSuppression config={config} updateConfig={updateConfig} data={data} />} */}
1214
+ {config.visualizationType === 'Line' && <PreliminaryData config={config} updateConfig={updateConfig} data={data} />}
1315
1215
  </AccordionItemPanel>
1316
1216
  </AccordionItem>
1317
1217
  )}
@@ -1489,7 +1389,7 @@ const EditorPanel = () => {
1489
1389
  <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />
1490
1390
  )}
1491
1391
  <TextField value={config.yAxis.numTicks} placeholder='Auto' type='number' section='yAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1492
- {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} />}
1493
1393
  <TextField
1494
1394
  value={config.yAxis.size}
1495
1395
  type='number'
@@ -1510,12 +1410,12 @@ const EditorPanel = () => {
1510
1410
  }
1511
1411
  />
1512
1412
  {config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
1513
- {(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} />}
1514
1414
  {config.isResponsiveTicks && config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && (
1515
1415
  <TextField
1516
1416
  value={config.xAxis.maxTickRotation}
1517
1417
  type='number'
1518
- min='0'
1418
+ min={0}
1519
1419
  section='xAxis'
1520
1420
  fieldName='maxTickRotation'
1521
1421
  label='Max Tick Rotation'
@@ -1539,7 +1439,7 @@ const EditorPanel = () => {
1539
1439
  {config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
1540
1440
  {visSupportsValueAxisGridLines() && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Show Gridlines' updateField={updateField} />}
1541
1441
  <CheckBox value={config.yAxis.enablePadding} section='yAxis' fieldName='enablePadding' label='Add Padding to Value Axis Scale' updateField={updateField} />
1542
- {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} />}
1543
1443
  </>
1544
1444
  )}
1545
1445
  <span className='divider-heading'>Number Formatting</span>
@@ -1606,9 +1506,9 @@ const EditorPanel = () => {
1606
1506
  {visSupportsValueAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
1607
1507
  {visSupportsValueAxisLabels() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
1608
1508
  {visSupportsValueAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
1609
- <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} />}
1610
1510
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1611
- <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} />}
1612
1512
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1613
1513
  {config.visualizationType === 'Deviation Bar' && (
1614
1514
  <>
@@ -1745,7 +1645,7 @@ const EditorPanel = () => {
1745
1645
  onClick={e => {
1746
1646
  e.preventDefault()
1747
1647
  const anchors = [...config.yAxis.anchors]
1748
- anchors.push({})
1648
+ anchors.push({} as Anchor)
1749
1649
  updateConfig({
1750
1650
  ...config,
1751
1651
  yAxis: {
@@ -1871,7 +1771,7 @@ const EditorPanel = () => {
1871
1771
  onClick={e => {
1872
1772
  e.preventDefault()
1873
1773
  const anchors = [...config.xAxis.anchors]
1874
- anchors.push({})
1774
+ anchors.push({} as Anchor)
1875
1775
  updateConfig({
1876
1776
  ...config,
1877
1777
  xAxis: {
@@ -1954,25 +1854,52 @@ const EditorPanel = () => {
1954
1854
  </AccordionItemPanel>
1955
1855
  </AccordionItem>
1956
1856
  )}
1957
- <AccordionItem>
1958
- <AccordionItemHeading>
1959
- <AccordionItemButton>
1960
- {config.visualizationType === 'Pie' ? 'Segments' : 'Date/Category Axis'}
1961
- {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1962
- </AccordionItemButton>
1963
- </AccordionItemHeading>
1964
- <AccordionItemPanel>
1965
- {config.visualizationType !== 'Pie' && (
1966
- <>
1967
- {config.visualizationType !== 'Forest Plot' && (
1968
- <Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={config.visualizationType !== 'Scatter Plot' ? ['categorical', 'date'] : ['categorical', 'continuous', 'date']} />
1969
- )}
1970
- <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' && (
1971
1898
  <Select
1972
- value={config.xAxis.dataKey || setCategoryAxis() || ''}
1899
+ value={config.xAxis.dataKey || ''}
1973
1900
  section='xAxis'
1974
1901
  fieldName='dataKey'
1975
- label='Data Key'
1902
+ label='Segment Labels'
1976
1903
  initial='Select'
1977
1904
  required={true}
1978
1905
  updateField={updateField}
@@ -1983,86 +1910,169 @@ const EditorPanel = () => {
1983
1910
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1984
1911
  </Tooltip.Target>
1985
1912
  <Tooltip.Content>
1986
- <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>
1987
1914
  </Tooltip.Content>
1988
1915
  </Tooltip>
1989
1916
  }
1990
1917
  />
1991
- </>
1992
- )}
1918
+ )}
1993
1919
 
1994
- {config.visualizationType === 'Pie' && (
1995
- <Select
1996
- value={config.xAxis.dataKey || ''}
1997
- section='xAxis'
1998
- fieldName='dataKey'
1999
- label='Segment Labels'
2000
- initial='Select'
2001
- required={true}
2002
- updateField={updateField}
2003
- options={getColumns(false)}
2004
- tooltip={
2005
- <Tooltip style={{ textTransform: 'none' }}>
2006
- <Tooltip.Target>
2007
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2008
- </Tooltip.Target>
2009
- <Tooltip.Content>
2010
- <p>Select the source row or column that contains the segment labels. Depending on the data structure, it may be listed as "Key."</p>
2011
- </Tooltip.Content>
2012
- </Tooltip>
2013
- }
2014
- />
2015
- )}
1920
+ {config.visualizationType !== 'Pie' && (
1921
+ <>
1922
+ <TextField value={config.xAxis.label} section='xAxis' fieldName='label' label='Label' updateField={updateField} />
2016
1923
 
2017
- {config.visualizationType !== 'Pie' && (
2018
- <>
2019
- <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
+ )}
2020
1981
 
2021
- {config.xAxis.type === 'continuous' && (
2022
- <>
2023
- <TextField
2024
- value={config.dataFormat.bottomPrefix}
2025
- section='dataFormat'
2026
- fieldName='bottomPrefix'
2027
- label='Prefix'
2028
- updateField={updateField}
2029
- tooltip={
2030
- <Tooltip style={{ textTransform: 'none' }}>
2031
- <Tooltip.Target>
2032
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2033
- </Tooltip.Target>
2034
- <Tooltip.Content>
2035
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
2036
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
2037
- </Tooltip.Content>
2038
- </Tooltip>
2039
- }
2040
- />
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
+ )}
2041
1995
 
2042
- <TextField
2043
- value={config.dataFormat.bottomSuffix}
2044
- section='dataFormat'
2045
- fieldName='bottomSuffix'
2046
- label='Suffix'
2047
- updateField={updateField}
2048
- tooltip={
2049
- <Tooltip style={{ textTransform: 'none' }}>
2050
- <Tooltip.Target>
2051
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2052
- </Tooltip.Target>
2053
- <Tooltip.Content>
2054
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
2055
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
2056
- </Tooltip.Content>
2057
- </Tooltip>
2058
- }
2059
- />
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
+ )}
2027
+
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
+ )}
2060
2051
 
2061
- <CheckBox
2062
- value={config.dataFormat.bottomAbbreviated}
2063
- section='dataFormat'
2064
- fieldName='bottomAbbreviated'
2065
- label='Abbreviate Axis Values'
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'
2066
2076
  updateField={updateField}
2067
2077
  tooltip={
2068
2078
  <Tooltip style={{ textTransform: 'none' }}>
@@ -2070,108 +2080,75 @@ const EditorPanel = () => {
2070
2080
  <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2071
2081
  </Tooltip.Target>
2072
2082
  <Tooltip.Content>
2073
- <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>
2074
2084
  </Tooltip.Content>
2075
2085
  </Tooltip>
2076
2086
  }
2077
2087
  />
2078
- </>
2079
- )}
2080
-
2081
- {config.xAxis.type === 'date' && (
2082
- <>
2083
- <p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
2084
- Format how charts should parse and display your dates using{' '}
2085
- <a href='https://github.com/d3/d3-time-format#locale_format' target='_blank' rel='noreferrer'>
2086
- these guidelines
2087
- </a>
2088
- .
2089
- </p>
2090
- <TextField value={config.xAxis.dateParseFormat} section='xAxis' fieldName='dateParseFormat' placeholder='Ex. %Y-%m-%d' label='Date Parse Format' updateField={updateField} />
2091
- <TextField value={config.xAxis.dateDisplayFormat} section='xAxis' fieldName='dateDisplayFormat' placeholder='Ex. %Y-%m-%d' label='Date Display Format' updateField={updateField} />
2092
- </>
2093
- )}
2094
-
2095
- <CheckBox
2096
- value={config.exclusions.active}
2097
- section='exclusions'
2098
- fieldName='active'
2099
- label={config.xAxis.type === 'date' ? 'Limit by start and/or end dates' : 'Exclude one or more values'}
2100
- tooltip={
2101
- <Tooltip style={{ textTransform: 'none' }}>
2102
- <Tooltip.Target>
2103
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2104
- </Tooltip.Target>
2105
- <Tooltip.Content>
2106
- <p>When this option is checked, you can select source-file values for exclusion from the date/category axis. </p>
2107
- </Tooltip.Content>
2108
- </Tooltip>
2109
- }
2110
- updateField={updateField}
2111
- />
2112
- {/* {visHasBrushChart && <CheckBox value={config.brush.active} section='brush' fieldName='active' label='Brush Slider ' updateField={updateField} />} */}
2113
-
2114
- {config.exclusions.active && (
2115
- <>
2116
- {config.xAxis.type === 'categorical' && (
2117
- <>
2118
- {config.exclusions.keys.length > 0 && (
2119
- <>
2120
- <fieldset>
2121
- <legend className='edit-label'>Excluded Keys</legend>
2122
- </fieldset>
2123
- <ExclusionsList />
2124
- </>
2125
- )}
2088
+ )}
2126
2089
 
2127
- <Select
2128
- fieldName='visualizationType'
2129
- label='Add Exclusion'
2130
- initial='Select'
2131
- onChange={e => {
2132
- if (e.target.value !== '' && e.target.value !== 'Select') {
2133
- addNewExclusion(e.target.value)
2134
- }
2135
- e.target.value = ''
2136
- }}
2137
- options={getDataValues(config.xAxis.dataKey, true)}
2138
- />
2139
- </>
2140
- )}
2141
-
2142
- {config.xAxis.type === 'date' && (
2143
- <>
2144
- <TextField type='date' section='exclusions' fieldName='dateStart' label='Start Date' updateField={updateField} value={config.exclusions.dateStart || ''} />
2145
- <TextField type='date' section='exclusions' fieldName='dateEnd' label='End Date' updateField={updateField} value={config.exclusions.dateEnd || ''} />
2146
- </>
2147
- )}
2148
- </>
2149
- )}
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
+ )}
2150
2102
 
2151
- {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} />}
2152
- {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} />}
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
+ )}
2153
2144
 
2154
- {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
2155
- {/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
2156
- {(config.xAxis.type === 'continuous' || config.forestPlot.type === 'Logarithmic') && (
2157
- <>
2158
- <CheckBox value={config.dataFormat.bottomCommas} section='dataFormat' fieldName='bottomCommas' label='Add commas' updateField={updateField} />
2159
- <TextField value={config.dataFormat.bottomRoundTo} type='number' section='dataFormat' fieldName='bottomRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
2160
- </>
2161
- )}
2162
- {visSupportsResponsiveTicks() && config.orientation === 'vertical' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
2163
- {(config.orientation === 'horizontal' || !config.isResponsiveTicks) && visSupportsDateCategoryTickRotation() && (
2164
- <TextField value={config.xAxis.tickRotation} type='number' min='0' section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />
2165
- )}
2166
- {config.orientation === 'vertical' && config.isResponsiveTicks && config.visualizationType !== 'Paired Bar' && (
2167
- <TextField
2168
- value={config.xAxis.maxTickRotation}
2169
- type='number'
2170
- min='0'
2171
- section='xAxis'
2172
- fieldName='maxTickRotation'
2173
- label='Max Tick Rotation'
2174
- 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'}
2175
2152
  updateField={updateField}
2176
2153
  tooltip={
2177
2154
  <Tooltip style={{ textTransform: 'none' }}>
@@ -2179,379 +2156,295 @@ const EditorPanel = () => {
2179
2156
  <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2180
2157
  </Tooltip.Target>
2181
2158
  <Tooltip.Content>
2182
- <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>
2183
2160
  </Tooltip.Content>
2184
2161
  </Tooltip>
2185
2162
  }
2186
2163
  />
2187
- )}
2188
-
2189
- {config.orientation === 'horizontal' ? (
2190
- <>
2191
- {visSupportsDateCategoryAxisLine() && <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2192
- {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
2193
- </>
2194
- ) : (
2195
- <>
2196
- {visSupportsDateCategoryAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2197
- {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
2198
- {visSupportsDateCategoryAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
2199
- </>
2200
- )}
2201
-
2202
- {config.series?.length === 1 && config.visualizationType === 'Bar' && (
2203
- <>
2204
- {/* HIGHLIGHTED BARS */}
2205
- <label htmlFor='barHighlight'>Bar Highlighting</label>
2206
- {config.series.length === 1 &&
2207
- highlightedBarValues.map((highlightedBarValue, i) => (
2208
- <fieldset>
2209
- <div className='edit-block' key={`highlighted-bar-${i}`}>
2210
- <button className='remove-column' onClick={e => handleRemoveHighlightedBar(e, i)}>
2211
- Remove
2212
- </button>
2213
- <p>Highlighted Bar {i + 1}</p>
2214
- <label>
2215
- <span className='edit-label column-heading'>Value</span>
2216
- <select value={config.highlightedBarValues[i].value} onChange={e => handleUpdateHighlightedBar(e, i)}>
2217
- <option value=''>- Select Value -</option>
2218
- {highlightedSeriesValues && [...new Set(highlightedSeriesValues)].sort().map(option => <option key={`special-class-value-option-${i}-${option}`}>{option}</option>)}
2219
- </select>
2220
- </label>
2221
- <label>
2222
- <span className='edit-label column-heading'>Color</span>
2223
- <input type='text' value={config.highlightedBarValues[i].color ? config.highlightedBarValues[i].color : ''} onChange={e => handleUpdateHighlightedBarColor(e, i)} />
2224
- </label>
2225
- <label>
2226
- <span className='edit-label column-heading'>Border Width</span>
2227
- <input max='5' min='0' type='number' value={config.highlightedBarValues[i].borderWidth ? config.highlightedBarValues[i].borderWidth : ''} onChange={e => handleUpdateHighlightedBorderWidth(e, i)} />
2228
- </label>
2229
- <label>
2230
- <span className='edit-label column-heading'>Legend Label</span>
2231
- <input type='text' value={config.highlightedBarValues[i].legendLabel ? config.highlightedBarValues[i].legendLabel : ''} onChange={e => handleHighlightedBarLegendLabel(e, i)} />
2232
- </label>
2233
- </div>
2234
- </fieldset>
2235
- ))}
2236
- <button className='btn full-width' onClick={e => handleAddNewHighlightedBar(e)}>
2237
- Add Highlighted Bar
2238
- </button>
2239
- </>
2240
- )}
2241
- </>
2242
- )}
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
+ )}
2243
2191
 
2244
- {config.visualizationType === 'Pie' && (
2245
- <>
2246
- <CheckBox
2247
- value={config.exclusions.active}
2248
- section='exclusions'
2249
- fieldName='active'
2250
- label={'Exclude one or more values'}
2251
- updateField={updateField}
2252
- tooltip={
2253
- <Tooltip style={{ textTransform: 'none' }}>
2254
- <Tooltip.Target>
2255
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2256
- </Tooltip.Target>
2257
- <Tooltip.Content>
2258
- <p>When this option is checked, you can select values for exclusion from the pie segments.</p>
2259
- </Tooltip.Content>
2260
- </Tooltip>
2261
- }
2262
- />
2263
- {config.exclusions.active && (
2264
- <>
2265
- {config.exclusions.keys.length > 0 && (
2266
- <>
2267
- <fieldset>
2268
- <legend className='edit-label'>Excluded Keys</legend>
2269
- </fieldset>
2270
- <ExclusionsList />
2271
- </>
2272
- )}
2273
-
2274
- <Select
2275
- fieldName='visualizationType'
2276
- label='Add Exclusion'
2277
- initial='Select'
2278
- onChange={e => {
2279
- if (e.target.value !== '' && e.target.value !== 'Select') {
2280
- addNewExclusion(e.target.value)
2281
- }
2282
- e.target.value = ''
2283
- }}
2284
- options={getDataValues(config.xAxis.dataKey, true)}
2285
- />
2286
- </>
2287
- )}
2288
- </>
2289
- )}
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>
2290
2251
 
2291
- {/* anchors */}
2292
- {visHasAnchors() && config.orientation !== 'horizontal' && (
2293
- <div className='edit-block'>
2294
- <span className='edit-label column-heading'>Anchors</span>
2295
- <Accordion allowZeroExpanded>
2296
- {config.xAxis?.anchors?.map((anchor, index) => (
2297
- <AccordionItem className='series-item series-item--chart' key={`xaxis-anchors-2-${index}`}>
2298
- <AccordionItemHeading className='series-item__title'>
2299
- <>
2300
- <AccordionItemButton className={'accordion__button accordion__button'}>
2301
- Anchor {index + 1}
2302
- <button
2303
- className='series-list__remove'
2304
- 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 => {
2305
2258
  e.preventDefault()
2306
- const copiedAnchorGroups = [...config.xAxis.anchors]
2307
- copiedAnchorGroups.splice(index, 1)
2259
+ const copiedAnchors = [...config.xAxis.anchors]
2260
+ copiedAnchors[index].color = e.target.value
2261
+ updateConfig({
2262
+ ...config,
2263
+ xAxis: {
2264
+ ...config.xAxis,
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
2308
2279
  updateConfig({
2309
2280
  ...config,
2310
2281
  xAxis: {
2311
2282
  ...config.xAxis,
2312
- anchors: copiedAnchorGroups
2283
+ anchors: copiedAnchors
2313
2284
  }
2314
2285
  })
2315
2286
  }}
2316
2287
  >
2317
- Remove
2318
- </button>
2319
- </AccordionItemButton>
2320
- </>
2321
- </AccordionItemHeading>
2322
- <AccordionItemPanel>
2323
- <label>
2324
- <span>Anchor Value</span>
2325
- <Tooltip style={{ textTransform: 'none' }}>
2326
- <Tooltip.Target>
2327
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2328
- </Tooltip.Target>
2329
- <Tooltip.Content>
2330
- <p>Enter the value as its shown in the data column</p>
2331
- </Tooltip.Content>
2332
- </Tooltip>
2333
- <input
2334
- type='text'
2335
- value={config.xAxis.anchors[index].value ? config.xAxis.anchors[index].value : ''}
2336
- onChange={e => {
2337
- e.preventDefault()
2338
- const copiedAnchors = [...config.xAxis.anchors]
2339
- copiedAnchors[index].value = e.target.value
2340
- updateConfig({
2341
- ...config,
2342
- xAxis: {
2343
- ...config.xAxis,
2344
- anchors: copiedAnchors
2345
- }
2346
- })
2347
- }}
2348
- />
2349
- </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>
2350
2298
 
2351
- <label>
2352
- <span>Anchor Color</span>
2353
- <input
2354
- type='text'
2355
- value={config.xAxis.anchors[index].color ? config.xAxis.anchors[index].color : ''}
2356
- onChange={e => {
2357
- e.preventDefault()
2358
- const copiedAnchors = [...config.xAxis.anchors]
2359
- copiedAnchors[index].color = e.target.value
2360
- updateConfig({
2361
- ...config,
2362
- xAxis: {
2363
- ...config.xAxis,
2364
- anchors: copiedAnchors
2365
- }
2366
- })
2367
- }}
2368
- />
2369
- </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
+ )}
2370
2318
 
2371
- <label>
2372
- Anchor Line Style
2373
- <select
2374
- value={config.xAxis.anchors[index].lineStyle || ''}
2375
- onChange={e => {
2376
- const copiedAnchors = [...config.xAxis.anchors]
2377
- copiedAnchors[index].lineStyle = e.target.value
2378
- updateConfig({
2379
- ...config,
2380
- xAxis: {
2381
- ...config.xAxis,
2382
- anchors: copiedAnchors
2383
- }
2384
- })
2385
- }}
2386
- >
2387
- <option>Select</option>
2388
- {lineOptions.map(line => (
2389
- <option key={line.key}>{line.value}</option>
2390
- ))}
2391
- </select>
2392
- </label>
2393
- </AccordionItemPanel>
2394
- </AccordionItem>
2395
- ))}
2396
- </Accordion>
2397
-
2398
- <button
2399
- className='btn full-width'
2400
- onClick={e => {
2401
- e.preventDefault()
2402
- const anchors = [...config.xAxis.anchors]
2403
- anchors.push({})
2404
- updateConfig({
2405
- ...config,
2406
- xAxis: {
2407
- ...config.xAxis,
2408
- anchors
2409
- }
2410
- })
2411
- }}
2412
- >
2413
- Add Anchor
2414
- </button>
2415
- </div>
2416
- )}
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>
2417
2377
 
2418
- {visHasAnchors() && config.orientation === 'horizontal' && (
2419
- <div className='edit-block'>
2420
- <span className='edit-label column-heading'>Anchors</span>
2421
- <Accordion allowZeroExpanded>
2422
- {config.yAxis?.anchors?.map((anchor, index) => (
2423
- <AccordionItem className='series-item series-item--chart' key={`accordion-yaxis-anchors-${index}`}>
2424
- <AccordionItemHeading className='series-item__title'>
2425
- <>
2426
- <AccordionItemButton className={'accordion__button accordion__button'}>
2427
- Anchor {index + 1}
2428
- <button
2429
- className='series-list__remove'
2430
- 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 => {
2431
2384
  e.preventDefault()
2432
- const copiedAnchorGroups = [...config.yAxis.anchors]
2433
- copiedAnchorGroups.splice(index, 1)
2385
+ const copiedAnchors = [...config.yAxis.anchors]
2386
+ copiedAnchors[index].color = e.target.value
2434
2387
  updateConfig({
2435
2388
  ...config,
2436
2389
  yAxis: {
2437
2390
  ...config.yAxis,
2438
- anchors: copiedAnchorGroups
2391
+ anchors: copiedAnchors
2439
2392
  }
2440
2393
  })
2441
2394
  }}
2442
- >
2443
- Remove
2444
- </button>
2445
- </AccordionItemButton>
2446
- </>
2447
- </AccordionItemHeading>
2448
- <AccordionItemPanel>
2449
- <label>
2450
- <span>Anchor Value</span>
2451
- <Tooltip style={{ textTransform: 'none' }}>
2452
- <Tooltip.Target>
2453
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2454
- </Tooltip.Target>
2455
- <Tooltip.Content>
2456
- <p>Enter the value as its shown in the data column</p>
2457
- </Tooltip.Content>
2458
- </Tooltip>
2459
- <input
2460
- type='text'
2461
- value={config.yAxis.anchors[index].value ? config.yAxis.anchors[index].value : ''}
2462
- onChange={e => {
2463
- e.preventDefault()
2464
- const copiedAnchors = [...config.yAxis.anchors]
2465
- copiedAnchors[index].value = e.target.value
2466
- updateConfig({
2467
- ...config,
2468
- yAxis: {
2469
- ...config.yAxis,
2470
- anchors: copiedAnchors
2471
- }
2472
- })
2473
- }}
2474
- />
2475
- </label>
2395
+ />
2396
+ </label>
2476
2397
 
2477
- <label>
2478
- <span>Anchor Color</span>
2479
- <input
2480
- type='text'
2481
- value={config.yAxis.anchors[index].color ? config.yAxis.anchors[index].color : ''}
2482
- onChange={e => {
2483
- e.preventDefault()
2484
- const copiedAnchors = [...config.yAxis.anchors]
2485
- copiedAnchors[index].color = e.target.value
2486
- updateConfig({
2487
- ...config,
2488
- yAxis: {
2489
- ...config.yAxis,
2490
- anchors: copiedAnchors
2491
- }
2492
- })
2493
- }}
2494
- />
2495
- </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>
2496
2424
 
2497
- <label>
2498
- Anchor Line Style
2499
- <select
2500
- value={config.yAxis.anchors[index].lineStyle || ''}
2501
- onChange={e => {
2502
- const copiedAnchors = [...config.yAxis.anchors]
2503
- copiedAnchors[index].lineStyle = e.target.value
2504
- updateConfig({
2505
- ...config,
2506
- yAxis: {
2507
- ...config.yAxis,
2508
- anchors: copiedAnchors
2509
- }
2510
- })
2511
- }}
2512
- >
2513
- <option>Select</option>
2514
- {lineOptions.map(line => (
2515
- <option key={line.key}>{line.value}</option>
2516
- ))}
2517
- </select>
2518
- </label>
2519
- </AccordionItemPanel>
2520
- </AccordionItem>
2521
- ))}
2522
- </Accordion>
2523
-
2524
- <button
2525
- className='btn full-width'
2526
- onClick={e => {
2527
- e.preventDefault()
2528
- const anchors = [...config.yAxis.anchors]
2529
- anchors.push({})
2530
- updateConfig({
2531
- ...config,
2532
- yAxis: {
2533
- ...config.yAxis,
2534
- anchors
2535
- }
2536
- })
2537
- }}
2538
- >
2539
- Add Anchor
2540
- </button>
2541
- </div>
2542
- )}
2543
- </AccordionItemPanel>
2544
- </AccordionItem>
2545
- {visSupportsRegions() && (
2546
- <AccordionItem>
2547
- <AccordionItemHeading>
2548
- <AccordionItemButton>Regions</AccordionItemButton>
2549
- </AccordionItemHeading>
2550
- <AccordionItemPanel>
2551
- <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
+ )}
2552
2444
  </AccordionItemPanel>
2553
2445
  </AccordionItem>
2554
- )}{' '}
2446
+ )}
2447
+ <Panels.Regions name='Regions' />
2555
2448
  {/* Columns */}
2556
2449
  {config.visualizationType !== 'Box Plot' && (
2557
2450
  <AccordionItem>
@@ -2588,12 +2481,28 @@ const EditorPanel = () => {
2588
2481
  <label>
2589
2482
  <span className='edit-label column-heading'>Column</span>
2590
2483
  <select
2591
- value={config.columns[val] ? config.columns[val].name : columnsOptions[0]}
2484
+ value={config.columns[val] ? config.columns[val].name : getColumns()[0]}
2592
2485
  onChange={event => {
2593
2486
  editColumn(val, 'name', event.target.value)
2594
2487
  }}
2595
2488
  >
2596
- {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
+ ))}
2597
2506
  </select>
2598
2507
  </label>
2599
2508
  <TextField value={config.columns[val].label} section='columns' subsection={val} fieldName='label' label='Label' updateField={updateField} />
@@ -2658,18 +2567,6 @@ const EditorPanel = () => {
2658
2567
  <span className='edit-label'>Show in Forest Plot</span>
2659
2568
  </label>
2660
2569
  </li>
2661
- <li>
2662
- <label className='checkbox'>
2663
- <input
2664
- type='checkbox'
2665
- checked={config.columns[val].tooltips || false}
2666
- onChange={event => {
2667
- updateSeriesTooltip(val, event.target.checked)
2668
- }}
2669
- />
2670
- <span className='edit-label'>Show in tooltip</span>
2671
- </label>
2672
- </li>
2673
2570
  <li>
2674
2571
  <label className='checkbox'>
2675
2572
  <input
@@ -2742,20 +2639,18 @@ const EditorPanel = () => {
2742
2639
  >
2743
2640
  Remove
2744
2641
  </button>
2745
- <label>
2746
- <span className='edit-label column-heading'>Category</span>
2747
- <TextField
2748
- value={val}
2749
- section='legend'
2750
- subsection={null}
2751
- fieldName='additionalCategories'
2752
- updateField={(section, subsection, fieldName, value) => {
2753
- const updatedAdditionaCategories = [...config.legend.additionalCategories]
2754
- updatedAdditionaCategories[i] = value
2755
- updateField(section, subsection, fieldName, updatedAdditionaCategories)
2756
- }}
2757
- />
2758
- </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
+ />
2759
2654
  </fieldset>
2760
2655
  ))}
2761
2656
  <button
@@ -2890,7 +2785,7 @@ const EditorPanel = () => {
2890
2785
  }}
2891
2786
  >
2892
2787
  <option value=''>- Select Option -</option>
2893
- {getFilters(true).map((dataKey, index) => (
2788
+ {getFilters().map((dataKey, index) => (
2894
2789
  <option value={dataKey} key={index}>
2895
2790
  {dataKey}
2896
2791
  </option>
@@ -2918,8 +2813,12 @@ const EditorPanel = () => {
2918
2813
  updateFilterProp('filterStyle', index, e.target.value)
2919
2814
  }}
2920
2815
  >
2921
- {filterStyleOptions.map(item => {
2922
- 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
+ )
2923
2822
  })}
2924
2823
  </select>
2925
2824
  </label>
@@ -2956,7 +2855,7 @@ const EditorPanel = () => {
2956
2855
  <Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
2957
2856
  {(provided, snapshot) => (
2958
2857
  <li>
2959
- <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}>
2960
2859
  {value}
2961
2860
  </div>
2962
2861
  </li>
@@ -3186,9 +3085,9 @@ const EditorPanel = () => {
3186
3085
  />
3187
3086
  </>
3188
3087
  )}
3189
- {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} />}
3190
3089
  {((config.visualizationType === 'Bar' && config.orientation !== 'horizontal') || config.visualizationType === 'Combo') && <TextField value={config.barThickness} type='number' fieldName='barThickness' label='Bar Thickness' updateField={updateField} />}
3191
- {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} />}
3192
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} />}
3193
3092
 
3194
3093
  {config.visualizationType === 'Spark Line' && (
@@ -3257,94 +3156,11 @@ const EditorPanel = () => {
3257
3156
  <AccordionItemButton>Data Table</AccordionItemButton>
3258
3157
  </AccordionItemHeading>
3259
3158
  <AccordionItemPanel>
3260
- <TextField
3261
- value={config.table.label}
3262
- updateField={updateField}
3263
- section='table'
3264
- fieldName='label'
3265
- id='tableLabel'
3266
- label='Data Table Title'
3267
- placeholder='Data Table'
3268
- tooltip={
3269
- <Tooltip style={{ textTransform: 'none' }}>
3270
- <Tooltip.Target>
3271
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3272
- </Tooltip.Target>
3273
- <Tooltip.Content>
3274
- <p>Label is required for Data Table for 508 Compliance</p>
3275
- </Tooltip.Content>
3276
- </Tooltip>
3277
- }
3278
- />
3279
- <CheckBox
3280
- value={config.table.show}
3281
- section='table'
3282
- fieldName='show'
3283
- label='Show Data Table'
3284
- updateField={updateField}
3285
- className='column-heading'
3286
- tooltip={
3287
- <Tooltip style={{ textTransform: 'none' }}>
3288
- <Tooltip.Target>
3289
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
3290
- </Tooltip.Target>
3291
- <Tooltip.Content>
3292
- <p>Hiding the data table may affect accessibility. An alternate form of accessing visualization data is a 508 requirement.</p>
3293
- </Tooltip.Content>
3294
- </Tooltip>
3295
- }
3296
- />
3297
- {config.visualizationType !== 'Box Plot' && (
3298
- <CheckBox
3299
- value={config.table.showVertical}
3300
- section='table'
3301
- fieldName='showVertical'
3302
- label='Show Vertical Data'
3303
- updateField={updateField}
3304
- className='column-heading'
3305
- tooltip={
3306
- <Tooltip style={{ textTransform: 'none' }}>
3307
- <Tooltip.Target>
3308
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
3309
- </Tooltip.Target>
3310
- <Tooltip.Content>
3311
- <p>This will draw the data table with vertical data instead of horizontal.</p>
3312
- </Tooltip.Content>
3313
- </Tooltip>
3314
- }
3315
- />
3316
- )}
3317
- <TextField value={config.table.indexLabel} section='table' fieldName='indexLabel' label='Index Column Header' updateField={updateField} />
3318
- <TextField
3319
- value={config.table.caption}
3320
- updateField={updateField}
3321
- section='table'
3322
- type='textarea'
3323
- fieldName='caption'
3324
- label='Screen Reader Description'
3325
- placeholder=' Data table'
3326
- tooltip={
3327
- <Tooltip style={{ textTransform: 'none' }}>
3328
- <Tooltip.Target>
3329
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3330
- </Tooltip.Target>
3331
- <Tooltip.Content>
3332
- <p>Enter a description of the data table to be read by screen readers.</p>
3333
- </Tooltip.Content>
3334
- </Tooltip>
3335
- }
3336
- />
3337
- <CheckBox value={config.table.limitHeight} section='table' fieldName='limitHeight' label='Limit Table Height' updateField={updateField} />
3338
- {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} />}
3339
- <CheckBox value={config.table.expanded} section='table' fieldName='expanded' label='Expanded by Default' updateField={updateField} />
3340
- {isDashboard && <CheckBox value={config.table.showDataTableLink} section='table' fieldName='showDataTableLink' label='Show Data Table Name & Link' updateField={updateField} />}
3341
- {isLoadedFromUrl && <CheckBox value={config.table.showDownloadUrl} section='table' fieldName='showDownloadUrl' label='Show URL to Automatically Updated Data' updateField={updateField} />}
3342
- <CheckBox value={config.table.download} section='table' fieldName='download' label='Show Download CSV Link' updateField={updateField} />
3343
- <CheckBox value={config.table.showDownloadImgButton} section='table' fieldName='showDownloadImgButton' label='Display Image Button' updateField={updateField} />
3344
- {/* <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} />{' '}
3345
3160
  </AccordionItemPanel>
3346
3161
  </AccordionItem>
3347
3162
  )}
3163
+ {/* {(config.visualizationType === 'Bar' || config.visualizationType === 'Line') && <Panels.DateHighlighting name='Date Highlighting' />} */}
3348
3164
  </Accordion>
3349
3165
  {config.type !== 'Spark Line' && <AdvancedEditor loadConfig={updateConfig} state={config} convertStateToConfig={convertStateToConfig} />}
3350
3166
  </section>