@cdc/chart 4.24.7 → 4.24.9

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 (51) hide show
  1. package/dist/cdcchart.js +40313 -37543
  2. package/examples/cases-year.json +13379 -0
  3. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +76 -15
  4. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json +5 -5
  5. package/index.html +17 -8
  6. package/package.json +2 -2
  7. package/src/CdcChart.tsx +383 -133
  8. package/src/_stories/Chart.Legend.Gradient.tsx +19 -0
  9. package/src/_stories/_mock/legend.gradient_mock.json +236 -0
  10. package/src/components/Annotations/components/AnnotationDraggable.tsx +64 -11
  11. package/src/components/Axis/Categorical.Axis.tsx +145 -0
  12. package/src/components/BarChart/components/BarChart.Horizontal.tsx +4 -3
  13. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +1 -1
  14. package/src/components/BarChart/components/BarChart.StackedVertical.tsx +2 -5
  15. package/src/components/BarChart/components/BarChart.Vertical.tsx +17 -8
  16. package/src/components/BarChart/helpers/index.ts +5 -16
  17. package/src/components/BrushChart.tsx +205 -0
  18. package/src/components/EditorPanel/EditorPanel.tsx +1766 -509
  19. package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +19 -5
  20. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +190 -37
  21. package/src/components/EditorPanel/components/Panels/Panel.Sankey.tsx +43 -7
  22. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -4
  23. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +1 -11
  24. package/src/components/EditorPanel/editor-panel.scss +16 -3
  25. package/src/components/EditorPanel/{useEditorPermissions.js → useEditorPermissions.ts} +90 -19
  26. package/src/components/Legend/Legend.Component.tsx +185 -193
  27. package/src/components/Legend/Legend.Suppression.tsx +146 -0
  28. package/src/components/Legend/Legend.tsx +21 -5
  29. package/src/components/Legend/helpers/index.ts +33 -3
  30. package/src/components/LegendWrapper.tsx +26 -0
  31. package/src/components/LineChart/LineChartProps.ts +1 -18
  32. package/src/components/LineChart/components/LineChart.BumpCircle.tsx +103 -0
  33. package/src/components/LineChart/components/LineChart.Circle.tsx +47 -8
  34. package/src/components/LineChart/helpers.ts +55 -11
  35. package/src/components/LineChart/index.tsx +113 -38
  36. package/src/components/LinearChart.tsx +1366 -0
  37. package/src/components/PieChart/PieChart.tsx +74 -17
  38. package/src/components/Sankey/index.tsx +22 -16
  39. package/src/components/Sparkline/components/SparkLine.tsx +2 -2
  40. package/src/data/initial-state.js +13 -3
  41. package/src/hooks/useLegendClasses.ts +52 -15
  42. package/src/hooks/useMinMax.ts +4 -4
  43. package/src/hooks/useScales.ts +34 -24
  44. package/src/hooks/useTooltip.tsx +85 -22
  45. package/src/scss/DataTable.scss +2 -1
  46. package/src/scss/main.scss +107 -14
  47. package/src/types/ChartConfig.ts +34 -8
  48. package/src/types/ChartContext.ts +5 -4
  49. package/examples/feature/line/line-chart.json +0 -449
  50. package/src/components/BrushHandle.jsx +0 -17
  51. package/src/components/LineChart/index.scss +0 -1
@@ -1,7 +1,14 @@
1
1
  import { useState, useEffect, useCallback, memo, useContext } from 'react'
2
2
  import { DragDropContext, Droppable } from '@hello-pangea/dnd'
3
+ import chroma from 'chroma-js'
3
4
  import { isDateScale } from '@cdc/core/helpers/cove/date'
4
- import { Accordion, AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
5
+ import {
6
+ Accordion,
7
+ AccordionItem,
8
+ AccordionItemHeading,
9
+ AccordionItemPanel,
10
+ AccordionItemButton
11
+ } from 'react-accessible-accordion'
5
12
  import Layout from '@cdc/core/components/Layout'
6
13
 
7
14
  // @cdc/core
@@ -14,6 +21,7 @@ import VizFilterEditor from '@cdc/core/components/EditorPanel/VizFilterEditor'
14
21
  import Tooltip from '@cdc/core/components/ui/Tooltip'
15
22
  import { Select, TextField, CheckBox } from '@cdc/core/components/EditorPanel/Inputs'
16
23
  import { viewports } from '@cdc/core/helpers/getViewport'
24
+ import { approvedCurveTypes } from '@cdc/core/helpers/lineChartHelpers'
17
25
 
18
26
  // chart components
19
27
  import Panels from './components/Panels'
@@ -110,7 +118,8 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
110
118
  lineCode: '',
111
119
  hideBarSymbol: false,
112
120
  hideLineStyle: false,
113
- circleSize: 6
121
+ circleSize: 6,
122
+ displayGray: true
114
123
  }
115
124
  preliminaryData.push(defaultValues)
116
125
  updateConfig({ ...config, preliminaryData })
@@ -136,10 +145,388 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
136
145
  return (
137
146
  <>
138
147
  {config.preliminaryData &&
139
- config.preliminaryData?.map(({ circleSize, column, displayLegend, displayTable, displayTooltip, label, seriesKey, style, symbol, type, value, hideBarSymbol, hideLineStyle }, i) => {
148
+ config.preliminaryData?.map(
149
+ (
150
+ {
151
+ displayGray,
152
+ circleSize,
153
+ column,
154
+ displayLegend,
155
+ displayTable,
156
+ displayTooltip,
157
+ label,
158
+ seriesKey,
159
+ style,
160
+ symbol,
161
+ type,
162
+ value,
163
+ hideBarSymbol,
164
+ hideLineStyle
165
+ },
166
+ i
167
+ ) => {
168
+ return (
169
+ <div key={`preliminaryData-${i}`} className='edit-block'>
170
+ <p> {type === 'suppression' ? 'Suppressed' : 'Effect'} Data</p>
171
+ <button
172
+ type='button'
173
+ className='remove-column'
174
+ onClick={event => {
175
+ event.preventDefault()
176
+ removeColumn(i)
177
+ }}
178
+ >
179
+ Remove
180
+ </button>
181
+
182
+ <Select
183
+ value={type}
184
+ initial={config.visualizationType == 'Bar' ? '' : 'Select'}
185
+ fieldName='type'
186
+ label='Type'
187
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
188
+ options={getTypeOptions()}
189
+ />
190
+ {type === 'suppression' ? (
191
+ <>
192
+ <Select
193
+ tooltip={
194
+ <Tooltip style={{ textTransform: 'none' }}>
195
+ <Tooltip.Target>
196
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
197
+ </Tooltip.Target>
198
+ <Tooltip.Content>
199
+ <p>
200
+ {' '}
201
+ Without a selected "Data Series", the suppression symbol will be applied for all series in
202
+ the current dataset visualization. However, choosing a specific "data series" will isolate
203
+ the suppression to that series.
204
+ </p>
205
+ </Tooltip.Content>
206
+ </Tooltip>
207
+ }
208
+ value={column}
209
+ initial='Select'
210
+ fieldName='column'
211
+ label='Add Data Series'
212
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
213
+ options={config.runtime?.seriesKeys}
214
+ />
215
+ <TextField
216
+ value={value}
217
+ fieldName='value'
218
+ label='Suppressed Data Value'
219
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
220
+ />
221
+ {(hasComboLineSeries || config.visualizationType === 'Line') && (
222
+ <>
223
+ <Select
224
+ tooltip={
225
+ <Tooltip style={{ textTransform: 'none' }}>
226
+ <Tooltip.Target>
227
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
228
+ </Tooltip.Target>
229
+ <Tooltip.Content>
230
+ <p>
231
+ The recommended approach for presenting data is to include a footnote indicating any
232
+ data suppression.
233
+ </p>
234
+ </Tooltip.Content>
235
+ </Tooltip>
236
+ }
237
+ value={style}
238
+ initial='Select'
239
+ fieldName='style'
240
+ label={'suppression line style'}
241
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
242
+ options={getStyleOptions(type)}
243
+ />
244
+ <CheckBox
245
+ value={hideLineStyle}
246
+ fieldName='hideLineStyle'
247
+ label='Hide Suppressed line Style'
248
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
249
+ />
250
+ </>
251
+ )}
252
+
253
+ {(hasComboBarSeries || config.visualizationType === 'Bar') && (
254
+ <>
255
+ <Select
256
+ tooltip={
257
+ <Tooltip style={{ textTransform: 'none' }}>
258
+ <Tooltip.Target>
259
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
260
+ </Tooltip.Target>
261
+ <Tooltip.Content>
262
+ <p>
263
+ A symbol is <i>required</i> to indicate suppressed data. We suggest "double
264
+ asterisks." If "double asterisks" are already used elsewhere (e.g., footnotes), please
265
+ select an alternative symbol from the menu to denote data suppression.
266
+ </p>
267
+ </Tooltip.Content>
268
+ </Tooltip>
269
+ }
270
+ value={symbol}
271
+ initial='Select'
272
+ fieldName='symbol'
273
+ label={config.visualizationType === 'Combo' ? 'suppression bar symbol' : 'suppression symbol'}
274
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
275
+ options={getSymbolOptions()}
276
+ />
277
+ <CheckBox
278
+ value={hideBarSymbol}
279
+ fieldName='hideBarSymbol'
280
+ label='Hide Suppressed Bar Symbol '
281
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
282
+ />
283
+ </>
284
+ )}
285
+
286
+ <TextField
287
+ tooltip={
288
+ <Tooltip style={{ textTransform: 'none' }}>
289
+ <Tooltip.Target>
290
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
291
+ </Tooltip.Target>
292
+ <Tooltip.Content>
293
+ <p>This label will display in the tooltip and legend.</p>
294
+ </Tooltip.Content>
295
+ </Tooltip>
296
+ }
297
+ value={label ? label : 'Suppressed'}
298
+ fieldName='label'
299
+ label='Suppressed Data Label'
300
+ placeholder=''
301
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
302
+ />
303
+ <CheckBox
304
+ display={config.visualizationSubType === 'regular'}
305
+ tooltip={
306
+ <Tooltip style={{ textTransform: 'none' }}>
307
+ <Tooltip.Target>
308
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
309
+ </Tooltip.Target>
310
+ <Tooltip.Content>
311
+ <p>
312
+ Deselecting the "Display In Tooltips" option prevents suppressed values from appearing in
313
+ tooltips.
314
+ </p>
315
+ </Tooltip.Content>
316
+ </Tooltip>
317
+ }
318
+ value={displayTooltip}
319
+ fieldName='displayTooltip'
320
+ label='Display in tooltips'
321
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
322
+ />
323
+ <CheckBox
324
+ display={config.visualizationSubType === 'regular'}
325
+ tooltip={
326
+ <Tooltip style={{ textTransform: 'none' }}>
327
+ <Tooltip.Target>
328
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
329
+ </Tooltip.Target>
330
+ <Tooltip.Content>
331
+ <p>
332
+ Deselecting "Display in Legend" indicates that you do not want to display suppressed data
333
+ in the legend.
334
+ </p>
335
+ </Tooltip.Content>
336
+ </Tooltip>
337
+ }
338
+ value={displayLegend}
339
+ fieldName='displayLegend'
340
+ label='Display in legend'
341
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
342
+ />
343
+ <CheckBox
344
+ display={config.visualizationSubType === 'regular'}
345
+ tooltip={
346
+ <Tooltip style={{ textTransform: 'none' }}>
347
+ <Tooltip.Target>
348
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
349
+ </Tooltip.Target>
350
+ <Tooltip.Content>
351
+ <p>
352
+ Deselecting "Display In Data Table" indicates that you do not want to display suppressed
353
+ data in the data table.
354
+ </p>
355
+ </Tooltip.Content>
356
+ </Tooltip>
357
+ }
358
+ value={displayTable}
359
+ fieldName='displayTable'
360
+ label='Display in table'
361
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
362
+ />
363
+ <CheckBox
364
+ display={config.visualizationSubType === 'regular'}
365
+ tooltip={
366
+ <Tooltip style={{ textTransform: 'none' }}>
367
+ <Tooltip.Target>
368
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
369
+ </Tooltip.Target>
370
+ <Tooltip.Content>
371
+ <p>Selecting this option will apply to chart, tooltip hover, legend, and data table.</p>
372
+ </Tooltip.Content>
373
+ </Tooltip>
374
+ }
375
+ value={displayGray}
376
+ fieldName='displayGray'
377
+ label='Highlight Suppressed Data In Gray'
378
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
379
+ />
380
+ </>
381
+ ) : (
382
+ <>
383
+ <Select
384
+ value={seriesKey}
385
+ initial='Select'
386
+ fieldName='seriesKey'
387
+ label='ASSOCIATE TO SERIES'
388
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
389
+ options={config.runtime.lineSeriesKeys ?? config.runtime?.seriesKeys}
390
+ />
391
+ <Select
392
+ value={column}
393
+ initial='Select'
394
+ fieldName='column'
395
+ label='COLUMN WITH CONFIGURATION VALUE'
396
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
397
+ options={getColumnOptions()}
398
+ />
399
+ <TextField
400
+ tooltip={
401
+ <Tooltip style={{ textTransform: 'none' }}>
402
+ <Tooltip.Target>
403
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
404
+ </Tooltip.Target>
405
+ <Tooltip.Content>
406
+ <p>
407
+ If 'Filled Circles' is selected as the style, this field is optional, and the style
408
+ 'Filled Circles' will apply to all points within the associated series data.
409
+ </p>
410
+ </Tooltip.Content>
411
+ </Tooltip>
412
+ }
413
+ value={value}
414
+ fieldName='value'
415
+ label='VALUE TO TRIGGER'
416
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
417
+ />
418
+ <Select
419
+ value={style}
420
+ initial='Select'
421
+ fieldName='style'
422
+ label='Style'
423
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
424
+ options={getStyleOptions(type)}
425
+ />
426
+ {style.includes('Circles') && (
427
+ <TextField
428
+ className='number-narrow'
429
+ type='number'
430
+ value={circleSize}
431
+ fieldName='circleSize'
432
+ label='circle size'
433
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
434
+ />
435
+ )}
436
+ {style !== 'Filled Circles' && (
437
+ <TextField
438
+ value={label}
439
+ fieldName='label'
440
+ label='Label'
441
+ placeholder=''
442
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
443
+ />
444
+ )}
445
+ </>
446
+ )}
447
+ </div>
448
+ )
449
+ }
450
+ )}
451
+
452
+ <button type='button' onClick={addColumn} className='btn full-width'>
453
+ {config.visualizationType === 'Line'
454
+ ? 'Add Special Line'
455
+ : config.visualizationType === 'Bar'
456
+ ? ' Add Special Bar'
457
+ : 'Add Special Bar/Line'}
458
+ </button>
459
+ </>
460
+ )
461
+ }
462
+
463
+ interface CategoricalAxisProps {
464
+ config: ChartConfig
465
+ updateConfig: Function
466
+ display: boolean
467
+ }
468
+
469
+ const CategoricalAxis: React.FC<CategoricalAxisProps> = ({ config, updateConfig, display }) => {
470
+ const maxHeight = config?.yAxis?.maxValue
471
+
472
+ const totalEnteredHeight =
473
+ config?.yAxis?.categories?.reduce((sum, obj) => sum + (parseFloat(obj.height) || 0), 0) || 0
474
+
475
+ const removeColumn = i => {
476
+ let categories = []
477
+
478
+ if (config.yAxis.categories) {
479
+ categories = [...config.yAxis.categories]
480
+ }
481
+
482
+ categories.splice(i, 1)
483
+
484
+ updateConfig({ ...config, yAxis: { ...config.yAxis, categories } })
485
+ }
486
+
487
+ const getDarkerColor = () => {
488
+ const timesDarkened = config.yAxis?.categories?.length
489
+ const darkeningFactor = 0.4
490
+ const baseColor = '#ddd'
491
+ return chroma(baseColor)
492
+ .darken(darkeningFactor * timesDarkened)
493
+ .hex()
494
+ }
495
+
496
+ const addColumn = () => {
497
+ const categories = config.yAxis.categories ? [...config.yAxis.categories] : []
498
+ const defaultValues = {
499
+ label: 'Label ' + Number(categories.length + 1),
500
+ height: '',
501
+ color: getDarkerColor()
502
+ }
503
+ categories.push(defaultValues)
504
+ updateConfig({ ...config, yAxis: { ...config.yAxis, categories: categories } })
505
+ }
506
+
507
+ const update = (fieldName, value, i) => {
508
+ let categories = []
509
+
510
+ if (config.yAxis.categories) {
511
+ categories = [...config.yAxis.categories]
512
+ }
513
+
514
+ categories[i][fieldName] = value
515
+
516
+ updateConfig({ ...config, yAxis: { ...config.yAxis, categories } })
517
+ }
518
+
519
+ if (!display) {
520
+ return <></>
521
+ }
522
+
523
+ return (
524
+ <>
525
+ {config.yAxis.type === 'categorical' &&
526
+ config.yAxis.categories?.map(({ label, color, height }, i) => {
140
527
  return (
141
528
  <div key={`preliminaryData-${i}`} className='edit-block'>
142
- <p> {type === 'suppression' ? 'Suppressed' : 'Effect'} Data</p>
529
+ <p>Axis Category {i + 1}</p>
143
530
  <button
144
531
  type='button'
145
532
  className='remove-column'
@@ -150,174 +537,53 @@ const PreliminaryData: React.FC<PreliminaryProps> = ({ config, updateConfig, dat
150
537
  >
151
538
  Remove
152
539
  </button>
153
-
154
- <Select value={type} initial={config.visualizationType == 'Bar' ? '' : 'Select'} fieldName='type' label='Type' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} options={getTypeOptions()} />
155
- {type === 'suppression' ? (
156
- <>
157
- <Select
158
- tooltip={
159
- <Tooltip style={{ textTransform: 'none' }}>
160
- <Tooltip.Target>
161
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
162
- </Tooltip.Target>
163
- <Tooltip.Content>
164
- <p> If no “Data Series" is selected, the symbol will be applied to "all" suppressed values indicated in the dataset. If you select a particular data series, there's no need to fill in “suppression line style” and “suppression symbol” below.</p>
165
- </Tooltip.Content>
166
- </Tooltip>
167
- }
168
- value={column}
169
- initial='Select'
170
- fieldName='column'
171
- label='Add Data Series'
172
- updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
173
- options={config.runtime?.seriesKeys}
174
- />
175
- <TextField value={value} fieldName='value' label='Suppressed Data Value' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} />
176
- {(hasComboLineSeries || config.visualizationType === 'Line') && (
177
- <>
178
- <Select
179
- tooltip={
180
- <Tooltip style={{ textTransform: 'none' }}>
181
- <Tooltip.Target>
182
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
183
- </Tooltip.Target>
184
- <Tooltip.Content>
185
- <p>The recommended approach for presenting data is to include a footnote indicating any data suppression.</p>
186
- </Tooltip.Content>
187
- </Tooltip>
188
- }
189
- value={style}
190
- initial='Select'
191
- fieldName='style'
192
- label={'suppression line style'}
193
- updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
194
- options={getStyleOptions(type)}
195
- />
196
- <CheckBox value={hideLineStyle} fieldName='hideLineStyle' label='Hide Suppressed line Style' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} />
197
- </>
198
- )}
199
-
200
- {(hasComboBarSeries || config.visualizationType === 'Bar') && (
201
- <>
202
- <Select
203
- tooltip={
204
- <Tooltip style={{ textTransform: 'none' }}>
205
- <Tooltip.Target>
206
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
207
- </Tooltip.Target>
208
- <Tooltip.Content>
209
- <p>The suggested method for presenting suppressed data is to use "double asterisks". If "double asterisks" are already used elsewhere (e.g., footnotes), please select an alternative symbol from the menu to denote data suppression.</p>
210
- </Tooltip.Content>
211
- </Tooltip>
212
- }
213
- value={symbol}
214
- initial='Select'
215
- fieldName='symbol'
216
- label={config.visualizationType === 'Combo' ? 'suppression bar symbol' : 'suppression symbol'}
217
- updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
218
- options={getSymbolOptions()}
219
- />
220
- <CheckBox value={hideBarSymbol} fieldName='hideBarSymbol' label='Hide Suppressed Bar Symbol ' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} />
221
- </>
222
- )}
223
-
224
- <TextField
225
- tooltip={
226
- <Tooltip style={{ textTransform: 'none' }}>
227
- <Tooltip.Target>
228
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
229
- </Tooltip.Target>
230
- <Tooltip.Content>
231
- <p>This label will display in the tooltip and legend.</p>
232
- </Tooltip.Content>
233
- </Tooltip>
234
- }
235
- value={label ? label : 'Suppressed'}
236
- fieldName='label'
237
- label='Suppressed Data Label'
238
- placeholder=''
239
- updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
240
- />
241
- <CheckBox
242
- tooltip={
243
- <Tooltip style={{ textTransform: 'none' }}>
244
- <Tooltip.Target>
245
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
246
- </Tooltip.Target>
247
- <Tooltip.Content>
248
- <p>Enabling this tooltip will provide a clearer indication of 'suppressed' or 'zero data' values, whichever is applicable. Deselecting 'Display In Tooltip' indicates that you do not want to display 'suppressed' or 'zero data' values in tooltips when hovering over them.</p>
249
- </Tooltip.Content>
250
- </Tooltip>
251
- }
252
- value={displayTooltip}
253
- fieldName='displayTooltip'
254
- label='Display in tooltips'
255
- updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
256
- />
257
- <CheckBox
258
- tooltip={
259
- <Tooltip style={{ textTransform: 'none' }}>
260
- <Tooltip.Target>
261
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
262
- </Tooltip.Target>
263
- <Tooltip.Content>
264
- <p>Deselecting "Display in Legend" indicates that you do not want to display suppressed data in the legend.</p>
265
- </Tooltip.Content>
266
- </Tooltip>
267
- }
268
- value={displayLegend}
269
- fieldName='displayLegend'
270
- label='Display in legend'
271
- updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
272
- />
273
- <CheckBox
274
- tooltip={
275
- <Tooltip style={{ textTransform: 'none' }}>
276
- <Tooltip.Target>
277
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
278
- </Tooltip.Target>
279
- <Tooltip.Content>
280
- <p>Deselecting "Display In Data Table" indicates that you do not want to display suppressed data in the data table.</p>
281
- </Tooltip.Content>
282
- </Tooltip>
283
- }
284
- value={displayTable}
285
- fieldName='displayTable'
286
- label='Display in table'
287
- updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
288
- />
289
- </>
290
- ) : (
291
- <>
292
- <Select value={seriesKey} initial='Select' fieldName='seriesKey' label='ASSOCIATE TO SERIES' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} options={config.runtime.lineSeriesKeys ?? config.runtime?.seriesKeys} />
293
- <Select value={column} initial='Select' fieldName='column' label='COLUMN WITH CONFIGURATION VALUE' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} options={getColumnOptions()} />
294
- <TextField
295
- tooltip={
296
- <Tooltip style={{ textTransform: 'none' }}>
297
- <Tooltip.Target>
298
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
299
- </Tooltip.Target>
300
- <Tooltip.Content>
301
- <p>If 'Filled Circles' is selected as the style, this field is optional, and the style 'Filled Circles' will apply to all points within the associated series data.</p>
302
- </Tooltip.Content>
303
- </Tooltip>
304
- }
305
- value={value}
306
- fieldName='value'
307
- label='VALUE TO TRIGGER'
308
- updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
309
- />
310
- <Select value={style} initial='Select' fieldName='style' label='Style' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} options={getStyleOptions(type)} />
311
- {style.includes('Circles') && <TextField className='number-narrow' type='number' value={circleSize} fieldName='circleSize' label='circle size' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} />}
312
- {style !== 'Filled Circles' && <TextField value={label} fieldName='label' label='Label' placeholder='' updateField={(_, __, fieldName, value) => update(fieldName, value, i)} />}
313
- </>
540
+ <TextField
541
+ tooltip={
542
+ <Tooltip style={{ textTransform: 'none' }}>
543
+ <Tooltip.Target>
544
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
545
+ </Tooltip.Target>
546
+ <Tooltip.Content>
547
+ <p>
548
+ {' '}
549
+ Category Height will be ignored for the last category. The last category will fill the rest of
550
+ the axis height.
551
+ </p>
552
+ </Tooltip.Content>
553
+ </Tooltip>
554
+ }
555
+ type='number'
556
+ value={height}
557
+ fieldName='height'
558
+ label='Category Height'
559
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
560
+ />
561
+ {Number(totalEnteredHeight) > Number(maxHeight) && config.yAxis.categories.length - 1 === i && (
562
+ <span style={{ color: 'red', display: 'block', fontSize: '15px' }}>
563
+ Update Max value to show all categories
564
+ </span>
314
565
  )}
566
+
567
+ <div className='two-col-inputs'>
568
+ <TextField
569
+ value={color}
570
+ fieldName='color'
571
+ label='Color'
572
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
573
+ />
574
+ <TextField
575
+ value={label}
576
+ fieldName='label'
577
+ label='Label'
578
+ updateField={(_, __, fieldName, value) => update(fieldName, value, i)}
579
+ />
580
+ </div>
315
581
  </div>
316
582
  )
317
583
  })}
318
584
 
319
585
  <button type='button' onClick={addColumn} className='btn full-width'>
320
- {config.visualizationType === 'Line' ? 'Add Special Line' : config.visualizationType === 'Bar' ? ' Add Special Bar' : 'Add Special Bar/Line'}
586
+ Add Axis Category
321
587
  </button>
322
588
  </>
323
589
  )
@@ -366,6 +632,7 @@ const EditorPanel = () => {
366
632
  visCanAnimate,
367
633
  visHasLegend,
368
634
  visHasLegendAxisAlign,
635
+ visHasLegendColorCategory,
369
636
  visHasBrushChart,
370
637
  visSupportsDateCategoryAxis,
371
638
  visSupportsValueAxisMin,
@@ -394,7 +661,9 @@ const EditorPanel = () => {
394
661
  visSupportsRankByValue,
395
662
  visSupportsResponsiveTicks,
396
663
  visSupportsDateCategoryHeight,
397
- visHasDataSuppression
664
+ visHasDataSuppression,
665
+ visHasCategoricalAxis,
666
+ visSupportsDynamicSeries
398
667
  } = useEditorPermissions()
399
668
 
400
669
  // when the visualization type changes we
@@ -407,7 +676,8 @@ const EditorPanel = () => {
407
676
  newSeries = config.series.map(series => {
408
677
  return {
409
678
  ...series,
410
- type: config.visualizationType === 'Combo' ? 'Bar' : config.visualizationType ? config.visualizationType : 'Bar',
679
+ type:
680
+ config.visualizationType === 'Combo' ? 'Bar' : config.visualizationType ? config.visualizationType : 'Bar',
411
681
  axis: 'Left'
412
682
  }
413
683
  })
@@ -483,7 +753,14 @@ const EditorPanel = () => {
483
753
  }
484
754
 
485
755
  const updateField = (section, subsection, fieldName, newValue) => {
486
- if (isDebug) console.log('#COVE: CHART: EditorPanel: section, subsection, fieldName, newValue', section, subsection, fieldName, newValue) // eslint-disable-line
756
+ if (isDebug)
757
+ console.log(
758
+ '#COVE: CHART: EditorPanel: section, subsection, fieldName, newValue',
759
+ section,
760
+ subsection,
761
+ fieldName,
762
+ newValue
763
+ ) // eslint-disable-line
487
764
 
488
765
  if (section === 'boxplot' && subsection === 'legend') {
489
766
  updateConfig({
@@ -599,7 +876,14 @@ const EditorPanel = () => {
599
876
  })
600
877
 
601
878
  if (config.visualizationType === 'Forecasting') {
602
- newSeries.push({ dataKey: seriesKey, type: config.visualizationType, stages: forecastingStageArr, stageColumn: seriesKey, axis: 'Left', tooltip: true })
879
+ newSeries.push({
880
+ dataKey: seriesKey,
881
+ type: config.visualizationType,
882
+ stages: forecastingStageArr,
883
+ stageColumn: seriesKey,
884
+ axis: 'Left',
885
+ tooltip: true
886
+ })
603
887
  } else {
604
888
  newSeries.push({ dataKey: seriesKey, type: config.visualizationType, axis: 'Left', tooltip: true })
605
889
  }
@@ -655,7 +939,14 @@ const EditorPanel = () => {
655
939
  if (filter) {
656
940
  const { lower, upper } = config.confidenceKeys || {}
657
941
  Object.keys(columns).forEach(key => {
658
- if ((config.series && config.series.filter(series => series.dataKey === key).length > 0) || (config.confidenceKeys && Object.keys(config.confidenceKeys).includes(key) && ((lower && upper) || lower || upper) && key !== lower && key !== upper)) {
942
+ if (
943
+ (config.series && config.series.filter(series => series.dataKey === key).length > 0) ||
944
+ (config.confidenceKeys &&
945
+ Object.keys(config.confidenceKeys).includes(key) &&
946
+ ((lower && upper) || lower || upper) &&
947
+ key !== lower &&
948
+ key !== upper)
949
+ ) {
659
950
  delete columns[key]
660
951
  }
661
952
  })
@@ -664,9 +955,37 @@ const EditorPanel = () => {
664
955
  return Object.keys(columns)
665
956
  }
666
957
 
667
- const getDataValueOptions = data => {
958
+ const getLegendStyleOptions = (option: 'style' | 'subStyle'): string[] => {
959
+ const options: string[] = []
960
+
961
+ switch (option) {
962
+ case 'style':
963
+ options.push('circles', 'boxes')
964
+ if (
965
+ config.visualizationType === 'Bar' &&
966
+ (!['right', 'left'].includes(config.legend.position) || !config.legend.position)
967
+ ) {
968
+ options.push('gradient')
969
+ }
970
+ if (config.visualizationType === 'Line') {
971
+ options.push('lines')
972
+ }
973
+ break
974
+ case 'subStyle':
975
+ if (config.visualizationType === 'Bar') {
976
+ options.push('linear blocks')
977
+ } else {
978
+ options.push('linear blocks', 'smooth')
979
+ }
980
+
981
+ break
982
+ }
983
+ return options
984
+ }
985
+
986
+ const getDataValueOptions = (data: Record<string, any>[]): string[] => {
668
987
  if (!data) return []
669
- const set = new Set()
988
+ const set = new Set<string>()
670
989
  for (let i = 0; i < data.length; i++) {
671
990
  for (const [key] of Object.entries(data[i])) {
672
991
  set.add(key)
@@ -853,7 +1172,9 @@ const EditorPanel = () => {
853
1172
  case config.visualizationType === 'Combo' && isAllLine && enteredValue > minVal:
854
1173
  message = 'Value should not exceed ' + minValue
855
1174
  break
856
- case (config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && minVal > 0 && enteredValue > 0:
1175
+ case (config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) &&
1176
+ minVal > 0 &&
1177
+ enteredValue > 0:
857
1178
  message = config.useLogScale ? 'Value must be equal to 0' : 'Value must be less than or equal to 0'
858
1179
  break
859
1180
  case config.visualizationType === 'Deviation Bar' && enteredValue >= Math.min(minVal, config.xAxis.target):
@@ -905,7 +1226,17 @@ const EditorPanel = () => {
905
1226
  if (isDebug) console.log('### COVE DEBUG: Chart: Setting default datacol=', setdatacol) // eslint-disable-line
906
1227
  }
907
1228
 
908
- const chartsWithOptions = ['Area Chart', 'Combo', 'Line', 'Bar', 'Forecasting', 'Scatter Plot', 'Paired Bar', 'Deviation Bar']
1229
+ const chartsWithOptions = [
1230
+ 'Bump Chart',
1231
+ 'Area Chart',
1232
+ 'Combo',
1233
+ 'Line',
1234
+ 'Bar',
1235
+ 'Forecasting',
1236
+ 'Scatter Plot',
1237
+ 'Paired Bar',
1238
+ 'Deviation Bar'
1239
+ ]
909
1240
 
910
1241
  const columnsOptions = [
911
1242
  <option value='' key={'Select Option'}>
@@ -1033,7 +1364,10 @@ const EditorPanel = () => {
1033
1364
  })
1034
1365
  }
1035
1366
 
1036
- const colorCodeByCategory = config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1
1367
+ const colorCodeByCategory =
1368
+ config.visualizationType === 'Bar' &&
1369
+ config.visualizationSubType === 'regular' &&
1370
+ config.runtime.seriesKeys.length === 1
1037
1371
  const getLegendColumns = () => {
1038
1372
  const colorCodeData = data.map(d => d[config.legend.colorCode])
1039
1373
  return colorCodeByCategory ? colorCodeData : getColumns(false).filter(d => d !== config.xAxis.dataKey)
@@ -1090,83 +1424,183 @@ const EditorPanel = () => {
1090
1424
  return (
1091
1425
  <EditorPanelContext.Provider value={editorContextValues}>
1092
1426
  <ErrorBoundary component='EditorPanel'>
1093
- <Layout.Sidebar displayPanel={displayPanel} isDashboard={isDashboard} title={'Configure Chart'} onBackClick={onBackClick}>
1427
+ <Layout.Sidebar
1428
+ displayPanel={displayPanel}
1429
+ isDashboard={isDashboard}
1430
+ title={'Configure Chart'}
1431
+ onBackClick={onBackClick}
1432
+ >
1094
1433
  <Accordion allowZeroExpanded={true}>
1095
1434
  <Panels.General name='General' />
1096
1435
  <Panels.ForestPlot name='Forest Plot Settings' />
1097
1436
  <Panels.Sankey name='Sankey' />
1098
- {config.visualizationType !== 'Pie' && config.visualizationType !== 'Forest Plot' && config.visualizationType !== 'Sankey' && (
1099
- <AccordionItem>
1100
- <AccordionItemHeading>
1101
- <AccordionItemButton>Data Series {(!config.series || config.series.length === 0 || (config.visualizationType === 'Paired Bar' && config.series.length < 2)) && <WarningImage width='25' className='warning-icon' />}</AccordionItemButton>
1102
- </AccordionItemHeading>
1103
- <AccordionItemPanel>
1104
- {(!config.series || config.series.length === 0) && config.visualizationType !== 'Paired Bar' && <p className='warning'>At least one series is required</p>}
1105
- {(!config.series || config.series.length === 0 || config.series.length < 2) && config.visualizationType === 'Paired Bar' && <p className='warning'>Select two data series for paired bar chart (e.g., Male and Female).</p>}
1106
- <>
1107
- <Select
1108
- fieldName='visualizationType'
1109
- label='Add Data Series'
1110
- initial='Select'
1111
- onChange={e => {
1112
- if (e.target.value !== '' && e.target.value !== 'Select') {
1113
- addNewSeries(e.target.value)
1114
- }
1115
- e.target.value = ''
1116
- }}
1117
- options={getColumns()}
1118
- />
1119
- {config.series && config.series.length !== 0 && (
1120
- <Panels.Series.Wrapper getColumns={getColumns}>
1121
- <fieldset>
1122
- <legend className='edit-label float-left'>Displaying</legend>
1123
- <Tooltip style={{ textTransform: 'none' }}>
1124
- <Tooltip.Target>
1125
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1126
- </Tooltip.Target>
1127
- <Tooltip.Content>
1128
- <p>A data series is a set of related data points plotted in a chart and typically represented in the chart legend.</p>
1129
- </Tooltip.Content>
1130
- </Tooltip>
1131
- </fieldset>
1132
-
1133
- <DragDropContext onDragEnd={({ source, destination }) => handleSeriesChange(source.index, destination.index)}>
1134
- <Droppable droppableId='filter_order'>
1135
- {/* prettier-ignore */}
1136
- {provided => {
1137
- return (
1138
- <ul {...provided.droppableProps} className='series-list' ref={provided.innerRef}>
1139
- <Panels.Series.List series={config.series} getItemStyle={getItemStyle} sortableItemStyles={sortableItemStyles} chartsWithOptions={chartsWithOptions} />
1140
- {provided.placeholder}
1141
- </ul>
1142
- )
1437
+ {config.visualizationType !== 'Pie' &&
1438
+ config.visualizationType !== 'Forest Plot' &&
1439
+ config.visualizationType !== 'Sankey' && (
1440
+ <AccordionItem>
1441
+ <AccordionItemHeading>
1442
+ <AccordionItemButton>
1443
+ Data Series{' '}
1444
+ {(!config.series ||
1445
+ config.series.length === 0 ||
1446
+ (config.visualizationType === 'Paired Bar' && config.series.length < 2)) &&
1447
+ !config.dynamicSeries && <WarningImage width='25' className='warning-icon' />}
1448
+ </AccordionItemButton>
1449
+ </AccordionItemHeading>
1450
+ <AccordionItemPanel>
1451
+ {visSupportsDynamicSeries() && (
1452
+ <CheckBox
1453
+ value={config.dynamicSeries}
1454
+ fieldName='dynamicSeries'
1455
+ label='Dynamically generate series'
1456
+ updateField={updateField}
1457
+ />
1458
+ )}
1459
+ {config.dynamicSeries && config.visualizationType === 'Line' && (
1460
+ <Select
1461
+ fieldName='dynamicSeriesType'
1462
+ value={config.dynamicSeriesType}
1463
+ label='Series Type'
1464
+ initial='Select'
1465
+ updateField={updateField}
1466
+ options={['Line', 'dashed-sm', 'dashed-md', 'dashed-lg']}
1467
+ />
1468
+ )}
1469
+ {config.dynamicSeries &&
1470
+ config.visualizationType === 'Line' &&
1471
+ config.dynamicSeriesType === 'Line' && (
1472
+ <Select
1473
+ fieldName='dynamicSeriesLineType'
1474
+ value={config.dynamicSeriesLineType ? config.dynamicSeriesLineType : 'curveLinear'}
1475
+ label='Line Type'
1476
+ initial='Select'
1477
+ updateField={updateField}
1478
+ options={Object.keys(approvedCurveTypes).map(curveName => approvedCurveTypes[curveName])}
1479
+ />
1480
+ )}
1481
+ {(!visSupportsDynamicSeries() || !config.dynamicSeries) && (
1482
+ <>
1483
+ {(!config.series || config.series.length === 0) &&
1484
+ !config.dynamicSeries &&
1485
+ config.visualizationType !== 'Paired Bar' && (
1486
+ <p className='warning'>At least one series is required</p>
1487
+ )}
1488
+ {(!config.series || config.series.length === 0 || config.series.length < 2) &&
1489
+ config.visualizationType === 'Paired Bar' && (
1490
+ <p className='warning'>
1491
+ Select two data series for paired bar chart (e.g., Male and Female).
1492
+ </p>
1493
+ )}
1494
+ <>
1495
+ <Select
1496
+ fieldName='visualizationType'
1497
+ label='Add Data Series'
1498
+ initial='Select'
1499
+ onChange={e => {
1500
+ if (e.target.value !== '' && e.target.value !== 'Select') {
1501
+ addNewSeries(e.target.value)
1502
+ }
1503
+ e.target.value = ''
1143
1504
  }}
1144
- </Droppable>
1145
- </DragDropContext>
1146
- </Panels.Series.Wrapper>
1505
+ options={getColumns()}
1506
+ />
1507
+ {config.series && config.series.length !== 0 && (
1508
+ <Panels.Series.Wrapper getColumns={getColumns}>
1509
+ <fieldset>
1510
+ <legend className='edit-label float-left'>Displaying</legend>
1511
+ <Tooltip style={{ textTransform: 'none' }}>
1512
+ <Tooltip.Target>
1513
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1514
+ </Tooltip.Target>
1515
+ <Tooltip.Content>
1516
+ <p>
1517
+ A data series is a set of related data points plotted in a chart and typically
1518
+ represented in the chart legend.
1519
+ </p>
1520
+ </Tooltip.Content>
1521
+ </Tooltip>
1522
+ </fieldset>
1523
+
1524
+ <DragDropContext
1525
+ onDragEnd={({ source, destination }) =>
1526
+ handleSeriesChange(source.index, destination.index)
1527
+ }
1528
+ >
1529
+ <Droppable droppableId='filter_order'>
1530
+ {/* prettier-ignore */}
1531
+ {provided => {
1532
+ return (
1533
+ <ul {...provided.droppableProps} className='series-list' ref={provided.innerRef}>
1534
+ <Panels.Series.List
1535
+ series={config.series}
1536
+ getItemStyle={getItemStyle}
1537
+ sortableItemStyles={sortableItemStyles}
1538
+ chartsWithOptions={chartsWithOptions}
1539
+ />
1540
+ {provided.placeholder}
1541
+ </ul>
1542
+ )
1543
+ }}
1544
+ </Droppable>
1545
+ </DragDropContext>
1546
+ </Panels.Series.Wrapper>
1547
+ )}
1548
+ </>
1549
+ {config.series && config.series.length <= 1 && config.visualizationType === 'Bar' && (
1550
+ <>
1551
+ <span className='divider-heading'>Confidence Keys</span>
1552
+ <Select
1553
+ value={config.confidenceKeys.upper || ''}
1554
+ section='confidenceKeys'
1555
+ fieldName='upper'
1556
+ label='Upper'
1557
+ updateField={updateField}
1558
+ initial='Select'
1559
+ options={getColumns()}
1560
+ />
1561
+ <Select
1562
+ value={config.confidenceKeys.lower || ''}
1563
+ section='confidenceKeys'
1564
+ fieldName='lower'
1565
+ label='Lower'
1566
+ updateField={updateField}
1567
+ initial='Select'
1568
+ options={getColumns()}
1569
+ />
1570
+ </>
1571
+ )}
1572
+ {visSupportsRankByValue() && config.series && config.series.length === 1 && (
1573
+ <Select
1574
+ fieldName='visualizationType'
1575
+ label='Rank by Value'
1576
+ initial='Select'
1577
+ onChange={e => sortSeries(e.target.value)}
1578
+ options={['asc', 'desc']}
1579
+ />
1580
+ )}
1581
+ {/* {visHasDataSuppression() && <DataSuppression config={config} updateConfig={updateConfig} data={data} />} */}
1582
+ {visSupportsPreliminaryData() && (
1583
+ <PreliminaryData config={config} updateConfig={updateConfig} data={data} />
1584
+ )}
1585
+ </>
1147
1586
  )}
1148
- </>
1149
- {config.series && config.series.length <= 1 && config.visualizationType === 'Bar' && (
1150
- <>
1151
- <span className='divider-heading'>Confidence Keys</span>
1152
- <Select value={config.confidenceKeys.upper || ''} section='confidenceKeys' fieldName='upper' label='Upper' updateField={updateField} initial='Select' options={getColumns()} />
1153
- <Select value={config.confidenceKeys.lower || ''} section='confidenceKeys' fieldName='lower' label='Lower' updateField={updateField} initial='Select' options={getColumns()} />
1154
- </>
1155
- )}
1156
- {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']} />}
1157
- {/* {visHasDataSuppression() && <DataSuppression config={config} updateConfig={updateConfig} data={data} />} */}
1158
- {visSupportsPreliminaryData() && <PreliminaryData config={config} updateConfig={updateConfig} data={data} />}
1159
- </AccordionItemPanel>
1160
- </AccordionItem>
1161
- )}
1587
+ </AccordionItemPanel>
1588
+ </AccordionItem>
1589
+ )}
1162
1590
  <Panels.BoxPlot name='Measures' />
1163
1591
  {/* Left Value Axis */}
1164
1592
  {visSupportsLeftValueAxis() && (
1165
1593
  <AccordionItem>
1166
1594
  <AccordionItemHeading>
1167
1595
  <AccordionItemButton>
1168
- {config.visualizationType === 'Pie' ? 'Data Format' : config.orientation === 'vertical' ? 'Left Value Axis' : 'Value Axis'}
1169
- {config.visualizationType === 'Pie' && !config.yAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1596
+ {config.visualizationType === 'Pie'
1597
+ ? 'Data Format'
1598
+ : config.orientation === 'vertical'
1599
+ ? 'Left Value Axis'
1600
+ : 'Value Axis'}
1601
+ {config.visualizationType === 'Pie' && !config.yAxis.dataKey && (
1602
+ <WarningImage width='25' className='warning-icon' />
1603
+ )}
1170
1604
  </AccordionItemButton>
1171
1605
  </AccordionItemHeading>
1172
1606
  <AccordionItemPanel>
@@ -1194,11 +1628,66 @@ const EditorPanel = () => {
1194
1628
  )}
1195
1629
  {config.visualizationType !== 'Pie' && (
1196
1630
  <>
1197
- <TextField value={config.yAxis.label} section='yAxis' fieldName='label' label='Label ' updateField={updateField} />
1198
- {config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && !['Box Plot', 'Deviation Bar', 'Forest Plot'].includes(config.visualizationType) && (
1199
- <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />
1200
- )}
1631
+ <label>
1632
+ <span className='edit-label'>
1633
+ Axis Type
1634
+ <Tooltip style={{ textTransform: 'none', display: 'inline-block' }}>
1635
+ <Tooltip.Target>
1636
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1637
+ </Tooltip.Target>
1638
+ <Tooltip.Content>
1639
+ Select 'Numeric (Linear Scale)' for uniform scaling, 'Numeric (Logarithmic Scale)' for
1640
+ exponential data, or 'Categorical' for discrete categories.
1641
+ </Tooltip.Content>
1642
+ </Tooltip>
1643
+ </span>
1644
+ <select
1645
+ value={config.yAxis.type}
1646
+ onChange={e =>
1647
+ updateConfig({
1648
+ ...config,
1649
+ yAxis: {
1650
+ ...config.yAxis,
1651
+ type: e.target.value
1652
+ }
1653
+ })
1654
+ }
1655
+ >
1656
+ <option value='linear'>Numeric (Linear Scale)</option>
1657
+ {config.visualizationSubType !== 'stacked' && (
1658
+ <option value='logarithmic'>Numeric (Logarithmic Scale)</option>
1659
+ )}
1660
+ {config.orientation !== 'horizontal' && <option value='categorical'>Categorical</option>}
1661
+ </select>
1662
+ </label>
1663
+ <CategoricalAxis
1664
+ config={config}
1665
+ updateConfig={updateConfig}
1666
+ data={data}
1667
+ display={visHasCategoricalAxis()}
1668
+ />
1669
+
1201
1670
  <TextField
1671
+ display={!visHasCategoricalAxis()}
1672
+ value={config.yAxis.label}
1673
+ section='yAxis'
1674
+ fieldName='label'
1675
+ label='Label '
1676
+ updateField={updateField}
1677
+ />
1678
+ {config.runtime.seriesKeys &&
1679
+ config.runtime.seriesKeys.length === 1 &&
1680
+ !['Box Plot', 'Deviation Bar', 'Forest Plot'].includes(config.visualizationType) && (
1681
+ <CheckBox
1682
+ value={config.isLegendValue}
1683
+ fieldName='isLegendValue'
1684
+ label='Use Legend Value in Hover'
1685
+ updateField={updateField}
1686
+ />
1687
+ )}
1688
+
1689
+ <TextField
1690
+ display={!visHasCategoricalAxis()}
1202
1691
  value={config.yAxis.numTicks}
1203
1692
  placeholder='Auto'
1204
1693
  type='number'
@@ -1209,10 +1698,16 @@ const EditorPanel = () => {
1209
1698
  tooltip={
1210
1699
  <Tooltip style={{ textTransform: 'none' }}>
1211
1700
  <Tooltip.Target>
1212
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1701
+ <Icon
1702
+ display='question'
1703
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
1704
+ />
1213
1705
  </Tooltip.Target>
1214
1706
  <Tooltip.Content>
1215
- <p>Apporoximate number of ticks. Other factors such as space available and data may change the exact number of ticks used.</p>
1707
+ <p>
1708
+ Apporoximate number of ticks. Other factors such as space available and data may change
1709
+ the exact number of ticks used.
1710
+ </p>
1216
1711
  </Tooltip.Content>
1217
1712
  </Tooltip>
1218
1713
  }
@@ -1229,7 +1724,10 @@ const EditorPanel = () => {
1229
1724
  tooltip={
1230
1725
  <Tooltip style={{ textTransform: 'none' }}>
1231
1726
  <Tooltip.Target>
1232
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1727
+ <Icon
1728
+ display='question'
1729
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
1730
+ />
1233
1731
  </Tooltip.Target>
1234
1732
  <Tooltip.Content>
1235
1733
  <p>{`Increase the size if elements in the ${config.orientation} axis are being crowded or hidden behind other elements. Decrease if less space is required for the value axis.`}</p>
@@ -1237,10 +1735,38 @@ const EditorPanel = () => {
1237
1735
  </Tooltip>
1238
1736
  }
1239
1737
  />
1240
- <TextField value={config.yAxis.labelOffset} section='yAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />
1241
- {config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
1242
- {(config.orientation === 'vertical' || !config.isResponsiveTicks) && <TextField value={config.yAxis.tickRotation || 0} type='number' min={0} section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1243
- {config.isResponsiveTicks && config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && (
1738
+ <TextField
1739
+ display={!visHasCategoricalAxis()}
1740
+ value={config.yAxis.labelOffset}
1741
+ section='yAxis'
1742
+ fieldName='labelOffset'
1743
+ label='Label offset'
1744
+ type='number'
1745
+ className='number-narrow'
1746
+ updateField={updateField}
1747
+ />
1748
+ {config.orientation === 'horizontal' && (
1749
+ <CheckBox
1750
+ value={config.isResponsiveTicks}
1751
+ fieldName='isResponsiveTicks'
1752
+ label='Use Responsive Ticks'
1753
+ updateField={updateField}
1754
+ />
1755
+ )}
1756
+ {(config.orientation === 'vertical' || !config.isResponsiveTicks) && (
1757
+ <TextField
1758
+ display={!visHasCategoricalAxis()}
1759
+ value={config.yAxis.tickRotation || 0}
1760
+ type='number'
1761
+ min={0}
1762
+ section='yAxis'
1763
+ fieldName='tickRotation'
1764
+ label='Tick rotation (Degrees)'
1765
+ className='number-narrow'
1766
+ updateField={updateField}
1767
+ />
1768
+ )}
1769
+ {config.isResponsiveTicks && config.orientation === 'horizontal' && (
1244
1770
  <TextField
1245
1771
  value={config.xAxis.maxTickRotation}
1246
1772
  type='number'
@@ -1253,7 +1779,10 @@ const EditorPanel = () => {
1253
1779
  tooltip={
1254
1780
  <Tooltip style={{ textTransform: 'none' }}>
1255
1781
  <Tooltip.Target>
1256
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1782
+ <Icon
1783
+ display='question'
1784
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
1785
+ />
1257
1786
  </Tooltip.Target>
1258
1787
  <Tooltip.Content>
1259
1788
  <p>Degrees ticks will be rotated if values overlap, especially in smaller viewports.</p>
@@ -1265,10 +1794,33 @@ const EditorPanel = () => {
1265
1794
 
1266
1795
  {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
1267
1796
  {/* <TextField value={config.yAxis.axisPadding} type='number' max={10} min={0} section='yAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
1268
- {visSupportsValueAxisGridLines() && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Show Gridlines' updateField={updateField} />}
1269
- <CheckBox value={config.yAxis.enablePadding} section='yAxis' fieldName='enablePadding' label='Add Padding to Value Axis Scale' updateField={updateField} />
1270
- {config.yAxis.enablePadding && <TextField type='number' section='yAxis' fieldName='scalePadding' label='Padding Percentage' className='number-narrow' updateField={updateField} value={config.yAxis.scalePadding} />}
1271
- {config.visualizationSubType === 'regular' && config.visualizationType !== 'Forest Plot' && <CheckBox value={config.useLogScale} fieldName='useLogScale' label='use logarithmic scale' updateField={updateField} />}
1797
+ {visSupportsValueAxisGridLines() && (
1798
+ <CheckBox
1799
+ value={config.yAxis.gridLines}
1800
+ section='yAxis'
1801
+ fieldName='gridLines'
1802
+ label='Show Gridlines'
1803
+ updateField={updateField}
1804
+ />
1805
+ )}
1806
+ <CheckBox
1807
+ value={config.yAxis.enablePadding}
1808
+ section='yAxis'
1809
+ fieldName='enablePadding'
1810
+ label='Add Padding to Value Axis Scale'
1811
+ updateField={updateField}
1812
+ />
1813
+ {config.yAxis.enablePadding && (
1814
+ <TextField
1815
+ type='number'
1816
+ section='yAxis'
1817
+ fieldName='scalePadding'
1818
+ label='Padding Percentage'
1819
+ className='number-narrow'
1820
+ updateField={updateField}
1821
+ value={config.yAxis.scalePadding}
1822
+ />
1823
+ )}
1272
1824
  </>
1273
1825
  )}
1274
1826
  <span className='divider-heading'>Number Formatting</span>
@@ -1281,7 +1833,10 @@ const EditorPanel = () => {
1281
1833
  tooltip={
1282
1834
  <Tooltip style={{ textTransform: 'none' }}>
1283
1835
  <Tooltip.Target>
1284
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1836
+ <Icon
1837
+ display='question'
1838
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
1839
+ />
1285
1840
  </Tooltip.Target>
1286
1841
  <Tooltip.Content>
1287
1842
  <p>{`Selecting this option will add commas to the left value axis, tooltip hover, and data table.`}</p>
@@ -1290,6 +1845,7 @@ const EditorPanel = () => {
1290
1845
  }
1291
1846
  />
1292
1847
  <CheckBox
1848
+ display={!visHasCategoricalAxis()}
1293
1849
  value={config.dataFormat.abbreviated}
1294
1850
  section='dataFormat'
1295
1851
  fieldName='abbreviated'
@@ -1298,7 +1854,10 @@ const EditorPanel = () => {
1298
1854
  tooltip={
1299
1855
  <Tooltip style={{ textTransform: 'none' }}>
1300
1856
  <Tooltip.Target>
1301
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1857
+ <Icon
1858
+ display='question'
1859
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
1860
+ />
1302
1861
  </Tooltip.Target>
1303
1862
  <Tooltip.Content>
1304
1863
  <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
@@ -1306,7 +1865,16 @@ const EditorPanel = () => {
1306
1865
  </Tooltip>
1307
1866
  }
1308
1867
  />
1309
- <TextField value={config.dataFormat.roundTo ? config.dataFormat.roundTo : 0} type='number' section='dataFormat' fieldName='roundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1868
+ <TextField
1869
+ value={config.dataFormat.roundTo ? config.dataFormat.roundTo : 0}
1870
+ type='number'
1871
+ section='dataFormat'
1872
+ fieldName='roundTo'
1873
+ label='Round to decimal point'
1874
+ className='number-narrow'
1875
+ updateField={updateField}
1876
+ min={0}
1877
+ />
1310
1878
  <div className='two-col-inputs'>
1311
1879
  <TextField
1312
1880
  value={config.dataFormat.prefix}
@@ -1320,8 +1888,12 @@ const EditorPanel = () => {
1320
1888
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1321
1889
  </Tooltip.Target>
1322
1890
  <Tooltip.Content>
1323
- {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1324
- {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
1891
+ {config.visualizationType === 'Pie' && (
1892
+ <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>
1893
+ )}
1894
+ {config.visualizationType !== 'Pie' && (
1895
+ <p>Enter a data prefix (such as "$"), if applicable.</p>
1896
+ )}
1325
1897
  </Tooltip.Content>
1326
1898
  </Tooltip>
1327
1899
  }
@@ -1338,8 +1910,12 @@ const EditorPanel = () => {
1338
1910
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1339
1911
  </Tooltip.Target>
1340
1912
  <Tooltip.Content>
1341
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1342
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1913
+ {config.visualizationType === 'Pie' && (
1914
+ <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>
1915
+ )}
1916
+ {config.visualizationType !== 'Pie' && (
1917
+ <p>Enter a data suffix (such as "%"), if applicable.</p>
1918
+ )}
1343
1919
  </Tooltip.Content>
1344
1920
  </Tooltip>
1345
1921
  }
@@ -1348,31 +1924,133 @@ const EditorPanel = () => {
1348
1924
 
1349
1925
  {config.orientation === 'horizontal' ? ( // horizontal - x is vertical y is horizontal
1350
1926
  <>
1351
- {visSupportsValueAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
1352
- {visSupportsValueAxisLabels() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Tick Labels' updateField={updateField} />}
1353
- {visSupportsValueAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
1354
- {visSupportsValueAxisMax() && <TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='max value' type='number' placeholder='Auto' updateField={updateField} />}
1927
+ {visSupportsValueAxisLine() && (
1928
+ <CheckBox
1929
+ value={config.xAxis.hideAxis}
1930
+ section='xAxis'
1931
+ fieldName='hideAxis'
1932
+ label='Hide Axis'
1933
+ updateField={updateField}
1934
+ />
1935
+ )}
1936
+ {visSupportsValueAxisLabels() && (
1937
+ <CheckBox
1938
+ value={config.xAxis.hideLabel}
1939
+ section='xAxis'
1940
+ fieldName='hideLabel'
1941
+ label='Hide Tick Labels'
1942
+ updateField={updateField}
1943
+ />
1944
+ )}
1945
+ {visSupportsValueAxisTicks() && (
1946
+ <CheckBox
1947
+ value={config.xAxis.hideTicks}
1948
+ section='xAxis'
1949
+ fieldName='hideTicks'
1950
+ label='Hide Ticks'
1951
+ updateField={updateField}
1952
+ />
1953
+ )}
1954
+ {visSupportsValueAxisMax() && (
1955
+ <TextField
1956
+ value={config.xAxis.max}
1957
+ section='xAxis'
1958
+ fieldName='max'
1959
+ label='max value'
1960
+ type='number'
1961
+ placeholder='Auto'
1962
+ updateField={updateField}
1963
+ />
1964
+ )}
1355
1965
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1356
- {visSupportsValueAxisMin() && <TextField value={config.xAxis.min} section='xAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />}
1966
+ {visSupportsValueAxisMin() && (
1967
+ <TextField
1968
+ value={config.xAxis.min}
1969
+ section='xAxis'
1970
+ fieldName='min'
1971
+ type='number'
1972
+ label='min value'
1973
+ placeholder='Auto'
1974
+ updateField={updateField}
1975
+ />
1976
+ )}
1357
1977
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1358
1978
  {config.visualizationType === 'Deviation Bar' && (
1359
1979
  <>
1360
- <TextField value={config.xAxis.target} section='xAxis' fieldName='target' type='number' label='Deviation point' placeholder='Auto' updateField={updateField} />
1361
- <TextField value={config.xAxis.targetLabel || 'Target'} section='xAxis' fieldName='targetLabel' type='text' label='Deviation point Label' updateField={updateField} />
1362
- <CheckBox value={config.xAxis.showTargetLabel} section='xAxis' fieldName='showTargetLabel' label='Show Deviation point label' updateField={updateField} />
1980
+ <TextField
1981
+ value={config.xAxis.target}
1982
+ section='xAxis'
1983
+ fieldName='target'
1984
+ type='number'
1985
+ label='Deviation point'
1986
+ placeholder='Auto'
1987
+ updateField={updateField}
1988
+ />
1989
+ <TextField
1990
+ value={config.xAxis.targetLabel || 'Target'}
1991
+ section='xAxis'
1992
+ fieldName='targetLabel'
1993
+ type='text'
1994
+ label='Deviation point Label'
1995
+ updateField={updateField}
1996
+ />
1997
+ <CheckBox
1998
+ value={config.xAxis.showTargetLabel}
1999
+ section='xAxis'
2000
+ fieldName='showTargetLabel'
2001
+ label='Show Deviation point label'
2002
+ updateField={updateField}
2003
+ />
1363
2004
  </>
1364
2005
  )}
1365
2006
  </>
1366
2007
  ) : (
1367
2008
  config.visualizationType !== 'Pie' && (
1368
2009
  <>
1369
- <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1370
- <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Tick Labels' updateField={updateField} />
1371
- <CheckBox value={config.yAxis.hideTicks} section='yAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
2010
+ <CheckBox
2011
+ display={!visHasCategoricalAxis()}
2012
+ value={config.yAxis.hideAxis}
2013
+ section='yAxis'
2014
+ fieldName='hideAxis'
2015
+ label='Hide Axis'
2016
+ updateField={updateField}
2017
+ />
2018
+ <CheckBox
2019
+ display={!visHasCategoricalAxis()}
2020
+ value={config.yAxis.hideLabel}
2021
+ section='yAxis'
2022
+ fieldName='hideLabel'
2023
+ label='Hide Tick Labels'
2024
+ updateField={updateField}
2025
+ />
2026
+ <CheckBox
2027
+ display={!visHasCategoricalAxis()}
2028
+ value={config.yAxis.hideTicks}
2029
+ section='yAxis'
2030
+ fieldName='hideTicks'
2031
+ label='Hide Ticks'
2032
+ updateField={updateField}
2033
+ />
1372
2034
 
1373
- <TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='left axis max value' placeholder='Auto' updateField={updateField} />
2035
+ <TextField
2036
+ value={config.yAxis.max}
2037
+ section='yAxis'
2038
+ fieldName='max'
2039
+ type='number'
2040
+ label='left axis max value'
2041
+ placeholder='Auto'
2042
+ updateField={updateField}
2043
+ />
1374
2044
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1375
- <TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='left axis min value' placeholder='Auto' updateField={updateField} />
2045
+ <TextField
2046
+ value={config.yAxis.min}
2047
+ section='yAxis'
2048
+ fieldName='min'
2049
+ type='number'
2050
+ label='left axis min value'
2051
+ placeholder='Auto'
2052
+ updateField={updateField}
2053
+ />
1376
2054
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1377
2055
  </>
1378
2056
  )
@@ -1641,14 +2319,60 @@ const EditorPanel = () => {
1641
2319
  <AccordionItemButton>Right Value Axis</AccordionItemButton>
1642
2320
  </AccordionItemHeading>
1643
2321
  <AccordionItemPanel>
1644
- <TextField value={config.yAxis.rightLabel} section='yAxis' fieldName='rightLabel' label='Label' updateField={updateField} />
1645
- <TextField value={config.yAxis.rightNumTicks} placeholder='Auto' type='number' section='yAxis' fieldName='rightNumTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1646
- <TextField value={config.yAxis.rightAxisSize} type='number' section='yAxis' fieldName='rightAxisSize' label='Size (Width)' className='number-narrow' updateField={updateField} />
1647
- <TextField value={config.yAxis.rightLabelOffsetSize} type='number' section='yAxis' fieldName='rightLabelOffsetSize' label='Label Offset' className='number-narrow' updateField={updateField} />
2322
+ <TextField
2323
+ value={config.yAxis.rightLabel}
2324
+ section='yAxis'
2325
+ fieldName='rightLabel'
2326
+ label='Label'
2327
+ updateField={updateField}
2328
+ />
2329
+ <TextField
2330
+ value={config.yAxis.rightNumTicks}
2331
+ placeholder='Auto'
2332
+ type='number'
2333
+ section='yAxis'
2334
+ fieldName='rightNumTicks'
2335
+ label='Number of ticks'
2336
+ className='number-narrow'
2337
+ updateField={updateField}
2338
+ />
2339
+ <TextField
2340
+ value={config.yAxis.rightAxisSize}
2341
+ type='number'
2342
+ section='yAxis'
2343
+ fieldName='rightAxisSize'
2344
+ label='Size (Width)'
2345
+ className='number-narrow'
2346
+ updateField={updateField}
2347
+ />
2348
+ <TextField
2349
+ value={config.yAxis.rightLabelOffsetSize}
2350
+ type='number'
2351
+ section='yAxis'
2352
+ fieldName='rightLabelOffsetSize'
2353
+ label='Label Offset'
2354
+ className='number-narrow'
2355
+ updateField={updateField}
2356
+ />
1648
2357
 
1649
2358
  <span className='divider-heading'>Number Formatting</span>
1650
- <CheckBox value={config.dataFormat.rightCommas} section='dataFormat' fieldName='rightCommas' label='Add commas' updateField={updateField} />
1651
- <TextField value={config.dataFormat.rightRoundTo} type='number' section='dataFormat' fieldName='rightRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
2359
+ <CheckBox
2360
+ value={config.dataFormat.rightCommas}
2361
+ section='dataFormat'
2362
+ fieldName='rightCommas'
2363
+ label='Add commas'
2364
+ updateField={updateField}
2365
+ />
2366
+ <TextField
2367
+ value={config.dataFormat.rightRoundTo}
2368
+ type='number'
2369
+ section='dataFormat'
2370
+ fieldName='rightRoundTo'
2371
+ label='Round to decimal point'
2372
+ className='number-narrow'
2373
+ updateField={updateField}
2374
+ min={0}
2375
+ />
1652
2376
  <div className='two-col-inputs'>
1653
2377
  <TextField
1654
2378
  value={config.dataFormat.rightPrefix}
@@ -1662,8 +2386,12 @@ const EditorPanel = () => {
1662
2386
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1663
2387
  </Tooltip.Target>
1664
2388
  <Tooltip.Content>
1665
- {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1666
- {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
2389
+ {config.visualizationType === 'Pie' && (
2390
+ <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>
2391
+ )}
2392
+ {config.visualizationType !== 'Pie' && (
2393
+ <p>Enter a data prefix (such as "$"), if applicable.</p>
2394
+ )}
1667
2395
  </Tooltip.Content>
1668
2396
  </Tooltip>
1669
2397
  }
@@ -1680,21 +2408,59 @@ const EditorPanel = () => {
1680
2408
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1681
2409
  </Tooltip.Target>
1682
2410
  <Tooltip.Content>
1683
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1684
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
2411
+ {config.visualizationType === 'Pie' && (
2412
+ <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>
2413
+ )}
2414
+ {config.visualizationType !== 'Pie' && (
2415
+ <p>Enter a data suffix (such as "%"), if applicable.</p>
2416
+ )}
1685
2417
  </Tooltip.Content>
1686
2418
  </Tooltip>
1687
2419
  }
1688
2420
  />
1689
2421
  </div>
1690
2422
 
1691
- <CheckBox value={config.yAxis.rightHideAxis} section='yAxis' fieldName='rightHideAxis' label='Hide Axis' updateField={updateField} />
1692
- <CheckBox value={config.yAxis.rightHideLabel} section='yAxis' fieldName='rightHideLabel' label='Hide Tick Labels' updateField={updateField} />
1693
- <CheckBox value={config.yAxis.rightHideTicks} section='yAxis' fieldName='rightHideTicks' label='Hide Ticks' updateField={updateField} />
2423
+ <CheckBox
2424
+ value={config.yAxis.rightHideAxis}
2425
+ section='yAxis'
2426
+ fieldName='rightHideAxis'
2427
+ label='Hide Axis'
2428
+ updateField={updateField}
2429
+ />
2430
+ <CheckBox
2431
+ value={config.yAxis.rightHideLabel}
2432
+ section='yAxis'
2433
+ fieldName='rightHideLabel'
2434
+ label='Hide Tick Labels'
2435
+ updateField={updateField}
2436
+ />
2437
+ <CheckBox
2438
+ value={config.yAxis.rightHideTicks}
2439
+ section='yAxis'
2440
+ fieldName='rightHideTicks'
2441
+ label='Hide Ticks'
2442
+ updateField={updateField}
2443
+ />
1694
2444
 
1695
- <TextField value={config.yAxis.max} section='yAxis' fieldName='rightMax' type='number' label='right axis max value' placeholder='Auto' updateField={updateField} />
2445
+ <TextField
2446
+ value={config.yAxis.max}
2447
+ section='yAxis'
2448
+ fieldName='rightMax'
2449
+ type='number'
2450
+ label='right axis max value'
2451
+ placeholder='Auto'
2452
+ updateField={updateField}
2453
+ />
1696
2454
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.rightMaxMessage}</span>
1697
- <TextField value={config.yAxis.min} section='yAxis' fieldName='rightMin' type='number' label='right axis min value' placeholder='Auto' updateField={updateField} />
2455
+ <TextField
2456
+ value={config.yAxis.min}
2457
+ section='yAxis'
2458
+ fieldName='rightMin'
2459
+ type='number'
2460
+ label='right axis min value'
2461
+ placeholder='Auto'
2462
+ updateField={updateField}
2463
+ />
1698
2464
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1699
2465
  </AccordionItemPanel>
1700
2466
  </AccordionItem>
@@ -1719,7 +2485,10 @@ const EditorPanel = () => {
1719
2485
  <Tooltip.Target>
1720
2486
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1721
2487
  </Tooltip.Target>
1722
- <Tooltip.Content>Linear scales are employed for quantitative data, while time scales are used for time-series data.</Tooltip.Content>
2488
+ <Tooltip.Content>
2489
+ Linear scales are employed for quantitative data, while time scales are used for
2490
+ time-series data.
2491
+ </Tooltip.Content>
1723
2492
  </Tooltip>
1724
2493
  </span>
1725
2494
  <select
@@ -1734,14 +2503,26 @@ const EditorPanel = () => {
1734
2503
  })
1735
2504
  }
1736
2505
  >
1737
- <option value='categorical'>Categorical (Linear Scale)</option>
1738
- <option value='date'>Date (Linear Scale)</option>
2506
+ {config.visualizationType !== 'Bump Chart' && (
2507
+ <option value='categorical'>Categorical (Linear Scale)</option>
2508
+ )}
2509
+ {config.visualizationType !== 'Bump Chart' && (
2510
+ <option value='date'>Date (Linear Scale)</option>
2511
+ )}
1739
2512
  <option value='date-time'>Date (Date Time Scale)</option>
1740
- {config.visualizationType === 'Scatter Plot' && <option value={'continuous'}>Continuous</option>}
2513
+ {config.visualizationType === 'Scatter Plot' && (
2514
+ <option value={'continuous'}>Continuous</option>
2515
+ )}
1741
2516
  </select>
1742
2517
  </label>
1743
2518
 
1744
- <CheckBox value={config.xAxis.manual} section='xAxis' fieldName='manual' label='Manual Ticks' updateField={updateField} />
2519
+ <CheckBox
2520
+ value={config.xAxis.manual}
2521
+ section='xAxis'
2522
+ fieldName='manual'
2523
+ label='Manual Ticks'
2524
+ updateField={updateField}
2525
+ />
1745
2526
 
1746
2527
  {visSupportsDateCategoryAxisPadding() && (
1747
2528
  <TextField
@@ -1759,7 +2540,10 @@ const EditorPanel = () => {
1759
2540
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1760
2541
  </Tooltip.Target>
1761
2542
  <Tooltip.Content>
1762
- <p>For use with date scale. Extends the earliest and latest dates represented on the scale by the percentage specified.</p>
2543
+ <p>
2544
+ For use with date scale. Extends the earliest and latest dates represented on the
2545
+ scale by the percentage specified.
2546
+ </p>
1763
2547
  </Tooltip.Content>
1764
2548
  </Tooltip>
1765
2549
  }
@@ -1806,7 +2590,10 @@ const EditorPanel = () => {
1806
2590
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1807
2591
  </Tooltip.Target>
1808
2592
  <Tooltip.Content>
1809
- <p>Select the source row or column that contains the segment labels. Depending on the data structure, it may be listed as "Key."</p>
2593
+ <p>
2594
+ Select the source row or column that contains the segment labels. Depending on the data
2595
+ structure, it may be listed as "Key."
2596
+ </p>
1810
2597
  </Tooltip.Content>
1811
2598
  </Tooltip>
1812
2599
  }
@@ -1815,7 +2602,13 @@ const EditorPanel = () => {
1815
2602
 
1816
2603
  {config.visualizationType !== 'Pie' && (
1817
2604
  <>
1818
- <TextField value={config.xAxis.label} section='xAxis' fieldName='label' label='Label' updateField={updateField} />
2605
+ <TextField
2606
+ value={config.xAxis.label}
2607
+ section='xAxis'
2608
+ fieldName='label'
2609
+ label='Label'
2610
+ updateField={updateField}
2611
+ />
1819
2612
 
1820
2613
  {config.xAxis.type === 'continuous' && (
1821
2614
  <>
@@ -1828,7 +2621,10 @@ const EditorPanel = () => {
1828
2621
  tooltip={
1829
2622
  <Tooltip style={{ textTransform: 'none' }}>
1830
2623
  <Tooltip.Target>
1831
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2624
+ <Icon
2625
+ display='question'
2626
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2627
+ />
1832
2628
  </Tooltip.Target>
1833
2629
  <Tooltip.Content>
1834
2630
  <p>Enter a data prefix (such as "$"), if applicable.</p>
@@ -1846,7 +2642,10 @@ const EditorPanel = () => {
1846
2642
  tooltip={
1847
2643
  <Tooltip style={{ textTransform: 'none' }}>
1848
2644
  <Tooltip.Target>
1849
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2645
+ <Icon
2646
+ display='question'
2647
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2648
+ />
1850
2649
  </Tooltip.Target>
1851
2650
  <Tooltip.Content>
1852
2651
  <p>Enter a data suffix (such as "%"), if applicable.</p>
@@ -1864,7 +2663,10 @@ const EditorPanel = () => {
1864
2663
  tooltip={
1865
2664
  <Tooltip style={{ textTransform: 'none' }}>
1866
2665
  <Tooltip.Target>
1867
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2666
+ <Icon
2667
+ display='question'
2668
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2669
+ />
1868
2670
  </Tooltip.Target>
1869
2671
  <Tooltip.Content>
1870
2672
  <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
@@ -1879,7 +2681,11 @@ const EditorPanel = () => {
1879
2681
  <>
1880
2682
  <p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
1881
2683
  Format how charts should parse and display your dates using{' '}
1882
- <a href='https://github.com/d3/d3-time-format#locale_format' target='_blank' rel='noreferrer'>
2684
+ <a
2685
+ href='https://github.com/d3/d3-time-format#locale_format'
2686
+ target='_blank'
2687
+ rel='noreferrer'
2688
+ >
1883
2689
  these guidelines
1884
2690
  </a>
1885
2691
  .
@@ -1888,10 +2694,16 @@ const EditorPanel = () => {
1888
2694
  tooltip={
1889
2695
  <Tooltip style={{ textTransform: 'none' }}>
1890
2696
  <Tooltip.Target>
1891
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2697
+ <Icon
2698
+ display='question'
2699
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2700
+ />
1892
2701
  </Tooltip.Target>
1893
2702
  <Tooltip.Content>
1894
- <p>This field specifies the pattern used to read and interpret dates in your dataset, ensuring the dates are correctly understood and processed. </p>
2703
+ <p>
2704
+ This field specifies the pattern used to read and interpret dates in your dataset,
2705
+ ensuring the dates are correctly understood and processed.{' '}
2706
+ </p>
1895
2707
  </Tooltip.Content>
1896
2708
  </Tooltip>
1897
2709
  }
@@ -1906,10 +2718,16 @@ const EditorPanel = () => {
1906
2718
  tooltip={
1907
2719
  <Tooltip style={{ textTransform: 'none' }}>
1908
2720
  <Tooltip.Target>
1909
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2721
+ <Icon
2722
+ display='question'
2723
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2724
+ />
1910
2725
  </Tooltip.Target>
1911
2726
  <Tooltip.Content>
1912
- <p> Adjusts the date display format on the axis for clear, visual date representation.</p>
2727
+ <p>
2728
+ {' '}
2729
+ Adjusts the date display format on the axis for clear, visual date representation.
2730
+ </p>
1913
2731
  </Tooltip.Content>
1914
2732
  </Tooltip>
1915
2733
  }
@@ -1924,10 +2742,16 @@ const EditorPanel = () => {
1924
2742
  tooltip={
1925
2743
  <Tooltip style={{ textTransform: 'none' }}>
1926
2744
  <Tooltip.Target>
1927
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2745
+ <Icon
2746
+ display='question'
2747
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2748
+ />
1928
2749
  </Tooltip.Target>
1929
2750
  <Tooltip.Content>
1930
- <p>Specify a custom format for displaying dates in data table. If left empty, dates will adopt the Axis Date Display format. </p>
2751
+ <p>
2752
+ Specify a custom format for displaying dates in data table. If left empty, dates
2753
+ will adopt the Axis Date Display format.{' '}
2754
+ </p>
1931
2755
  </Tooltip.Content>
1932
2756
  </Tooltip>
1933
2757
  }
@@ -1942,10 +2766,16 @@ const EditorPanel = () => {
1942
2766
  tooltip={
1943
2767
  <Tooltip style={{ textTransform: 'none' }}>
1944
2768
  <Tooltip.Target>
1945
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2769
+ <Icon
2770
+ display='question'
2771
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2772
+ />
1946
2773
  </Tooltip.Target>
1947
2774
  <Tooltip.Content>
1948
- <p>Specify a custom format for displaying dates on hovers. If left empty, dates will adopt the Axis Date Display format. </p>
2775
+ <p>
2776
+ Specify a custom format for displaying dates on hovers. If left empty, dates will
2777
+ adopt the Axis Date Display format.{' '}
2778
+ </p>
1949
2779
  </Tooltip.Content>
1950
2780
  </Tooltip>
1951
2781
  }
@@ -1963,218 +2793,389 @@ const EditorPanel = () => {
1963
2793
  value={config.exclusions.active}
1964
2794
  section='exclusions'
1965
2795
  fieldName='active'
1966
- label={config.xAxis.type === 'date' ? 'Limit by start and/or end dates' : 'Exclude one or more values'}
2796
+ label={
2797
+ config.xAxis.type === 'date'
2798
+ ? 'Limit by start and/or end dates'
2799
+ : 'Exclude one or more values'
2800
+ }
1967
2801
  tooltip={
1968
2802
  <Tooltip style={{ textTransform: 'none' }}>
1969
2803
  <Tooltip.Target>
1970
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2804
+ <Icon
2805
+ display='question'
2806
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2807
+ />
1971
2808
  </Tooltip.Target>
1972
2809
  <Tooltip.Content>
1973
- <p>When this option is checked, you can select source-file values for exclusion from the date/category axis. </p>
2810
+ <p>
2811
+ When this option is checked, you can select source-file values for exclusion from the
2812
+ date/category axis.{' '}
2813
+ </p>
1974
2814
  </Tooltip.Content>
1975
2815
  </Tooltip>
1976
2816
  }
1977
2817
  updateField={updateField}
1978
2818
  />
1979
- {false && visHasBrushChart && (
2819
+ {visHasBrushChart() && (
1980
2820
  <CheckBox
1981
2821
  value={config.brush?.active}
1982
2822
  section='brush'
1983
2823
  fieldName='active'
1984
2824
  label='Brush Slider '
1985
2825
  updateField={updateField}
1986
- tooltip={
1987
- <Tooltip style={{ textTransform: 'none' }}>
1988
- <Tooltip.Target>
1989
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1990
- </Tooltip.Target>
1991
- <Tooltip.Content>
1992
- <p>Use the brush slider to narrow down your data view to specific values along the axis. This tool is useful for examining detailed data segments within the larger dataset. </p>
1993
- </Tooltip.Content>
1994
- </Tooltip>
1995
- }
2826
+ tooltip={
2827
+ <Tooltip style={{ textTransform: 'none' }}>
2828
+ <Tooltip.Target>
2829
+ <Icon
2830
+ display='question'
2831
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2832
+ />
2833
+ </Tooltip.Target>
2834
+ <Tooltip.Content>
2835
+ <p>
2836
+ Use the brush slider to narrow down your data view to specific values along the axis.
2837
+ This tool is useful for examining detailed data segments within the larger dataset.{' '}
2838
+ </p>
2839
+ </Tooltip.Content>
2840
+ </Tooltip>
2841
+ }
2842
+ />
2843
+ )}
2844
+
2845
+ {config.exclusions.active && (
2846
+ <>
2847
+ {config.xAxis.type === 'categorical' && (
2848
+ <>
2849
+ {config.exclusions.keys.length > 0 && (
2850
+ <>
2851
+ <fieldset>
2852
+ <legend className='edit-label'>Excluded Keys</legend>
2853
+ </fieldset>
2854
+ <ExclusionsList />
2855
+ </>
2856
+ )}
2857
+
2858
+ <Select
2859
+ fieldName='visualizationType'
2860
+ label='Add Exclusion'
2861
+ initial='Select'
2862
+ onChange={e => {
2863
+ if (e.target.value !== '' && e.target.value !== 'Select') {
2864
+ addNewExclusion(e.target.value)
2865
+ }
2866
+ e.target.value = ''
2867
+ }}
2868
+ options={getDataValues(config.xAxis.dataKey, true)}
2869
+ />
2870
+ </>
2871
+ )}
2872
+
2873
+ {config.xAxis.type === 'date' && (
2874
+ <>
2875
+ <TextField
2876
+ type='date'
2877
+ section='exclusions'
2878
+ fieldName='dateStart'
2879
+ label='Start Date'
2880
+ updateField={updateField}
2881
+ value={config.exclusions.dateStart || ''}
2882
+ />
2883
+ <TextField
2884
+ type='date'
2885
+ section='exclusions'
2886
+ fieldName='dateEnd'
2887
+ label='End Date'
2888
+ updateField={updateField}
2889
+ value={config.exclusions.dateEnd || ''}
2890
+ />
2891
+ </>
2892
+ )}
2893
+ </>
2894
+ )}
2895
+
2896
+ {visSupportsDateCategoryNumTicks() &&
2897
+ config.xAxis.type !== 'date-time' &&
2898
+ config.xAxis.manual && (
2899
+ <>
2900
+ <TextField
2901
+ value={config.xAxis.manualStep}
2902
+ placeholder='Auto'
2903
+ type='number'
2904
+ min={1}
2905
+ section='xAxis'
2906
+ fieldName='manualStep'
2907
+ label='Step count'
2908
+ className='number-narrow'
2909
+ updateField={updateField}
2910
+ tooltip={
2911
+ <Tooltip style={{ textTransform: 'none' }}>
2912
+ <Tooltip.Target>
2913
+ <Icon
2914
+ display='question'
2915
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2916
+ />
2917
+ </Tooltip.Target>
2918
+ <Tooltip.Content>
2919
+ <p>
2920
+ Number of data points which are assigned a tick, starting from the right most data
2921
+ point. Value of 1 will show a tick at every data point, value of 2 will show a
2922
+ tick for every other, etc.
2923
+ </p>
2924
+ </Tooltip.Content>
2925
+ </Tooltip>
2926
+ }
2927
+ />
2928
+ <div className='viewport-overrides'>
2929
+ <label>
2930
+ <button
2931
+ onClick={() => setDisplayViewportOverrides(!displayViewportOverrides)}
2932
+ className='edit-label'
2933
+ >
2934
+ Step Count: viewport overrides{' '}
2935
+ <span style={{ transform: `rotate(${displayViewportOverrides ? '90deg' : '0deg'})` }}>
2936
+ &gt;
2937
+ </span>
2938
+ </button>
2939
+ </label>
2940
+ {displayViewportOverrides && (
2941
+ <div className='edit-block'>
2942
+ {Object.keys(viewports).map(viewport => (
2943
+ <TextField
2944
+ key={`viewport-step-count-input-${viewport}`}
2945
+ value={
2946
+ config.xAxis.viewportStepCount
2947
+ ? config.xAxis.viewportStepCount[viewport]
2948
+ : undefined
2949
+ }
2950
+ placeholder='Auto'
2951
+ type='number'
2952
+ label={viewport}
2953
+ className='number-narrow'
2954
+ updateField={(section, fieldName, label, val) =>
2955
+ updateViewportOverrides('viewportStepCount', viewport, val)
2956
+ }
2957
+ />
2958
+ ))}
2959
+ </div>
2960
+ )}
2961
+ </div>
2962
+ </>
2963
+ )}
2964
+ {visSupportsDateCategoryNumTicks() &&
2965
+ (config.xAxis.type === 'date-time' || !config.xAxis.manual) && (
2966
+ <>
2967
+ <TextField
2968
+ value={config.xAxis.numTicks}
2969
+ placeholder='Auto'
2970
+ type='number'
2971
+ min={1}
2972
+ section='xAxis'
2973
+ fieldName='numTicks'
2974
+ label='Number of ticks'
2975
+ className='number-narrow'
2976
+ updateField={updateField}
2977
+ tooltip={
2978
+ <Tooltip style={{ textTransform: 'none' }}>
2979
+ <Tooltip.Target>
2980
+ <Icon
2981
+ display='question'
2982
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
2983
+ />
2984
+ </Tooltip.Target>
2985
+ <Tooltip.Content>
2986
+ <p>
2987
+ Apporoximate number of ticks. Other factors such as space available and data may
2988
+ change the exact number of ticks used. To enforce an exact number of ticks, check
2989
+ "Manual Ticks" above.
2990
+ </p>
2991
+ </Tooltip.Content>
2992
+ </Tooltip>
2993
+ }
2994
+ />
2995
+ <div className='viewport-overrides'>
2996
+ <label>
2997
+ <button
2998
+ onClick={() => setDisplayViewportOverrides(!displayViewportOverrides)}
2999
+ className='edit-label'
3000
+ >
3001
+ Number of ticks: viewport overrides{' '}
3002
+ <span style={{ transform: `rotate(${displayViewportOverrides ? '90deg' : '0deg'})` }}>
3003
+ &gt;
3004
+ </span>
3005
+ </button>
3006
+ </label>
3007
+ {displayViewportOverrides && (
3008
+ <div className='edit-block'>
3009
+ {Object.keys(viewports).map(viewport => (
3010
+ <TextField
3011
+ key={`viewport-num-ticks-input-${viewport}`}
3012
+ value={
3013
+ config.xAxis.viewportNumTicks
3014
+ ? config.xAxis.viewportNumTicks[viewport]
3015
+ : undefined
3016
+ }
3017
+ placeholder='Auto'
3018
+ type='number'
3019
+ label={viewport}
3020
+ className='number-narrow'
3021
+ updateField={(section, fieldName, label, val) =>
3022
+ updateViewportOverrides('viewportNumTicks', viewport, val)
3023
+ }
3024
+ />
3025
+ ))}
3026
+ </div>
3027
+ )}
3028
+ </div>
3029
+ </>
3030
+ )}
3031
+ {visSupportsDateCategoryHeight() && (
3032
+ <TextField
3033
+ value={config.xAxis.size}
3034
+ type='number'
3035
+ min={0}
3036
+ section='xAxis'
3037
+ fieldName='size'
3038
+ label={config.orientation === 'horizontal' ? 'Size (Width)' : 'Size (Height)'}
3039
+ className='number-narrow'
3040
+ updateField={updateField}
1996
3041
  />
1997
3042
  )}
3043
+ <TextField
3044
+ value={config.xAxis.labelOffset}
3045
+ section='xAxis'
3046
+ fieldName='labelOffset'
3047
+ label='Label offset'
3048
+ type='number'
3049
+ className='number-narrow'
3050
+ updateField={updateField}
3051
+ />
1998
3052
 
1999
- {config.exclusions.active && (
3053
+ {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
3054
+ {/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
3055
+ {(config.xAxis.type === 'continuous' || config.forestPlot.type === 'Logarithmic') && (
2000
3056
  <>
2001
- {config.xAxis.type === 'categorical' && (
2002
- <>
2003
- {config.exclusions.keys.length > 0 && (
2004
- <>
2005
- <fieldset>
2006
- <legend className='edit-label'>Excluded Keys</legend>
2007
- </fieldset>
2008
- <ExclusionsList />
2009
- </>
2010
- )}
2011
-
2012
- <Select
2013
- fieldName='visualizationType'
2014
- label='Add Exclusion'
2015
- initial='Select'
2016
- onChange={e => {
2017
- if (e.target.value !== '' && e.target.value !== 'Select') {
2018
- addNewExclusion(e.target.value)
2019
- }
2020
- e.target.value = ''
2021
- }}
2022
- options={getDataValues(config.xAxis.dataKey, true)}
2023
- />
2024
- </>
2025
- )}
2026
-
2027
- {config.xAxis.type === 'date' && (
2028
- <>
2029
- <TextField type='date' section='exclusions' fieldName='dateStart' label='Start Date' updateField={updateField} value={config.exclusions.dateStart || ''} />
2030
- <TextField type='date' section='exclusions' fieldName='dateEnd' label='End Date' updateField={updateField} value={config.exclusions.dateEnd || ''} />
2031
- </>
2032
- )}
3057
+ <CheckBox
3058
+ value={config.dataFormat.bottomCommas}
3059
+ section='dataFormat'
3060
+ fieldName='bottomCommas'
3061
+ label='Add commas'
3062
+ updateField={updateField}
3063
+ />
3064
+ <TextField
3065
+ value={config.dataFormat.bottomRoundTo}
3066
+ type='number'
3067
+ section='dataFormat'
3068
+ fieldName='bottomRoundTo'
3069
+ label='Round to decimal point'
3070
+ className='number-narrow'
3071
+ updateField={updateField}
3072
+ min={0}
3073
+ />
2033
3074
  </>
2034
3075
  )}
2035
-
2036
- {visSupportsDateCategoryNumTicks() && config.xAxis.type !== 'date-time' && config.xAxis.manual && (
2037
- <>
3076
+ {visSupportsResponsiveTicks() &&
3077
+ config.orientation === 'vertical' &&
3078
+ config.visualizationType !== 'Paired Bar' && (
3079
+ <CheckBox
3080
+ value={config.isResponsiveTicks}
3081
+ fieldName='isResponsiveTicks'
3082
+ label='Use Responsive Ticks'
3083
+ updateField={updateField}
3084
+ />
3085
+ )}
3086
+ {(config.orientation === 'horizontal' || !config.isResponsiveTicks) &&
3087
+ visSupportsDateCategoryTickRotation() && (
2038
3088
  <TextField
2039
- value={config.xAxis.manualStep}
2040
- placeholder='Auto'
3089
+ value={config.xAxis.tickRotation}
2041
3090
  type='number'
2042
- min={1}
3091
+ min={0}
2043
3092
  section='xAxis'
2044
- fieldName='manualStep'
2045
- label='Step count'
3093
+ fieldName='tickRotation'
3094
+ label='Tick rotation (Degrees)'
2046
3095
  className='number-narrow'
2047
3096
  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
- <p>Number of data points which are assigned a tick, starting from the right most data point. Value of 1 will show a tick at every data point, value of 2 will show a tick for every other, etc.</p>
2055
- </Tooltip.Content>
2056
- </Tooltip>
2057
- }
2058
3097
  />
2059
- <div className='viewport-overrides'>
2060
- <label>
2061
- <button onClick={() => setDisplayViewportOverrides(!displayViewportOverrides)} className='edit-label'>
2062
- Step Count: viewport overrides <span style={{ transform: `rotate(${displayViewportOverrides ? '90deg' : '0deg'})` }}>&gt;</span>
2063
- </button>
2064
- </label>
2065
- {displayViewportOverrides && (
2066
- <div className='edit-block'>
2067
- {Object.keys(viewports).map(viewport => (
2068
- <TextField
2069
- key={`viewport-step-count-input-${viewport}`}
2070
- value={config.xAxis.viewportStepCount ? config.xAxis.viewportStepCount[viewport] : undefined}
2071
- placeholder='Auto'
2072
- type='number'
2073
- label={viewport}
2074
- className='number-narrow'
2075
- updateField={(section, fieldName, label, val) => updateViewportOverrides('viewportStepCount', viewport, val)}
2076
- />
2077
- ))}
2078
- </div>
2079
- )}
2080
- </div>
2081
- </>
2082
- )}
2083
- {visSupportsDateCategoryNumTicks() && (config.xAxis.type === 'date-time' || !config.xAxis.manual) && (
2084
- <>
3098
+ )}
3099
+ {config.orientation === 'vertical' &&
3100
+ config.isResponsiveTicks &&
3101
+ config.visualizationType !== 'Paired Bar' && (
2085
3102
  <TextField
2086
- value={config.xAxis.numTicks}
2087
- placeholder='Auto'
3103
+ value={config.xAxis.maxTickRotation}
2088
3104
  type='number'
2089
- min={1}
3105
+ min={0}
2090
3106
  section='xAxis'
2091
- fieldName='numTicks'
2092
- label='Number of ticks'
3107
+ fieldName='maxTickRotation'
3108
+ label='Max Tick Rotation'
2093
3109
  className='number-narrow'
2094
3110
  updateField={updateField}
2095
3111
  tooltip={
2096
3112
  <Tooltip style={{ textTransform: 'none' }}>
2097
3113
  <Tooltip.Target>
2098
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
3114
+ <Icon
3115
+ display='question'
3116
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
3117
+ />
2099
3118
  </Tooltip.Target>
2100
3119
  <Tooltip.Content>
2101
- <p>Apporoximate number of ticks. Other factors such as space available and data may change the exact number of ticks used. To enforce an exact number of ticks, check "Manual Ticks" above.</p>
3120
+ <p>
3121
+ Degrees ticks will be rotated if values overlap, especially in smaller viewports.
3122
+ </p>
2102
3123
  </Tooltip.Content>
2103
3124
  </Tooltip>
2104
3125
  }
2105
3126
  />
2106
- <div className='viewport-overrides'>
2107
- <label>
2108
- <button onClick={() => setDisplayViewportOverrides(!displayViewportOverrides)} className='edit-label'>
2109
- Number of ticks: viewport overrides <span style={{ transform: `rotate(${displayViewportOverrides ? '90deg' : '0deg'})` }}>&gt;</span>
2110
- </button>
2111
- </label>
2112
- {displayViewportOverrides && (
2113
- <div className='edit-block'>
2114
- {Object.keys(viewports).map(viewport => (
2115
- <TextField
2116
- key={`viewport-num-ticks-input-${viewport}`}
2117
- value={config.xAxis.viewportNumTicks ? config.xAxis.viewportNumTicks[viewport] : undefined}
2118
- placeholder='Auto'
2119
- type='number'
2120
- label={viewport}
2121
- className='number-narrow'
2122
- updateField={(section, fieldName, label, val) => updateViewportOverrides('viewportNumTicks', viewport, val)}
2123
- />
2124
- ))}
2125
- </div>
2126
- )}
2127
- </div>
2128
- </>
2129
- )}
2130
- {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} />}
2131
- <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />
2132
-
2133
- {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
2134
- {/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
2135
- {(config.xAxis.type === 'continuous' || config.forestPlot.type === 'Logarithmic') && (
2136
- <>
2137
- <CheckBox value={config.dataFormat.bottomCommas} section='dataFormat' fieldName='bottomCommas' label='Add commas' updateField={updateField} />
2138
- <TextField value={config.dataFormat.bottomRoundTo} type='number' section='dataFormat' fieldName='bottomRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
2139
- </>
2140
- )}
2141
- {visSupportsResponsiveTicks() && config.orientation === 'vertical' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
2142
- {(config.orientation === 'horizontal' || !config.isResponsiveTicks) && visSupportsDateCategoryTickRotation() && (
2143
- <TextField value={config.xAxis.tickRotation} type='number' min={0} section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />
2144
- )}
2145
- {config.orientation === 'vertical' && config.isResponsiveTicks && config.visualizationType !== 'Paired Bar' && (
2146
- <TextField
2147
- value={config.xAxis.maxTickRotation}
2148
- type='number'
2149
- min={0}
2150
- section='xAxis'
2151
- fieldName='maxTickRotation'
2152
- label='Max Tick Rotation'
2153
- className='number-narrow'
2154
- updateField={updateField}
2155
- tooltip={
2156
- <Tooltip style={{ textTransform: 'none' }}>
2157
- <Tooltip.Target>
2158
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2159
- </Tooltip.Target>
2160
- <Tooltip.Content>
2161
- <p>Degrees ticks will be rotated if values overlap, especially in smaller viewports.</p>
2162
- </Tooltip.Content>
2163
- </Tooltip>
2164
- }
2165
- />
2166
- )}
3127
+ )}
2167
3128
 
2168
3129
  {config.orientation === 'horizontal' ? (
2169
3130
  <>
2170
- {visSupportsDateCategoryAxisLine() && <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2171
- {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Tick Labels' updateField={updateField} />}
3131
+ {visSupportsDateCategoryAxisLine() && (
3132
+ <CheckBox
3133
+ value={config.yAxis.hideAxis}
3134
+ section='yAxis'
3135
+ fieldName='hideAxis'
3136
+ label='Hide Axis'
3137
+ updateField={updateField}
3138
+ />
3139
+ )}
3140
+ {visSupportsDateCategoryAxisLabel() && (
3141
+ <CheckBox
3142
+ value={config.yAxis.hideLabel}
3143
+ section='yAxis'
3144
+ fieldName='hideLabel'
3145
+ label='Hide Tick Labels'
3146
+ updateField={updateField}
3147
+ />
3148
+ )}
2172
3149
  </>
2173
3150
  ) : (
2174
3151
  <>
2175
- {visSupportsDateCategoryAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2176
- {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Tick Labels' updateField={updateField} />}
2177
- {visSupportsDateCategoryAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
3152
+ {visSupportsDateCategoryAxisLine() && (
3153
+ <CheckBox
3154
+ value={config.xAxis.hideAxis}
3155
+ section='xAxis'
3156
+ fieldName='hideAxis'
3157
+ label='Hide Axis'
3158
+ updateField={updateField}
3159
+ />
3160
+ )}
3161
+ {visSupportsDateCategoryAxisLabel() && (
3162
+ <CheckBox
3163
+ value={config.xAxis.hideLabel}
3164
+ section='xAxis'
3165
+ fieldName='hideLabel'
3166
+ label='Hide Tick Labels'
3167
+ updateField={updateField}
3168
+ />
3169
+ )}
3170
+ {visSupportsDateCategoryAxisTicks() && (
3171
+ <CheckBox
3172
+ value={config.xAxis.hideTicks}
3173
+ section='xAxis'
3174
+ fieldName='hideTicks'
3175
+ label='Hide Ticks'
3176
+ updateField={updateField}
3177
+ />
3178
+ )}
2178
3179
  </>
2179
3180
  )}
2180
3181
 
@@ -2192,22 +3193,54 @@ const EditorPanel = () => {
2192
3193
  <p>Highlighted Bar {i + 1}</p>
2193
3194
  <label>
2194
3195
  <span className='edit-label column-heading'>Value</span>
2195
- <select value={config.highlightedBarValues[i].value} onChange={e => handleUpdateHighlightedBar(e, i)}>
3196
+ <select
3197
+ value={config.highlightedBarValues[i].value}
3198
+ onChange={e => handleUpdateHighlightedBar(e, i)}
3199
+ >
2196
3200
  <option value=''>- Select Value -</option>
2197
- {highlightedSeriesValues && [...new Set(highlightedSeriesValues)].sort().map(option => <option key={`special-class-value-option-${i}-${option}`}>{option}</option>)}
3201
+ {highlightedSeriesValues &&
3202
+ [...new Set(highlightedSeriesValues)]
3203
+ .sort()
3204
+ .map(option => (
3205
+ <option key={`special-class-value-option-${i}-${option}`}>{option}</option>
3206
+ ))}
2198
3207
  </select>
2199
3208
  </label>
2200
3209
  <label>
2201
3210
  <span className='edit-label column-heading'>Color</span>
2202
- <input type='text' value={config.highlightedBarValues[i].color ? config.highlightedBarValues[i].color : ''} onChange={e => handleUpdateHighlightedBarColor(e, i)} />
3211
+ <input
3212
+ type='text'
3213
+ value={
3214
+ config.highlightedBarValues[i].color ? config.highlightedBarValues[i].color : ''
3215
+ }
3216
+ onChange={e => handleUpdateHighlightedBarColor(e, i)}
3217
+ />
2203
3218
  </label>
2204
3219
  <label>
2205
3220
  <span className='edit-label column-heading'>Border Width</span>
2206
- <input max='5' min='0' type='number' value={config.highlightedBarValues[i].borderWidth ? config.highlightedBarValues[i].borderWidth : ''} onChange={e => handleUpdateHighlightedBorderWidth(e, i)} />
3221
+ <input
3222
+ max='5'
3223
+ min='0'
3224
+ type='number'
3225
+ value={
3226
+ config.highlightedBarValues[i].borderWidth
3227
+ ? config.highlightedBarValues[i].borderWidth
3228
+ : ''
3229
+ }
3230
+ onChange={e => handleUpdateHighlightedBorderWidth(e, i)}
3231
+ />
2207
3232
  </label>
2208
3233
  <label>
2209
3234
  <span className='edit-label column-heading'>Legend Label</span>
2210
- <input type='text' value={config.highlightedBarValues[i].legendLabel ? config.highlightedBarValues[i].legendLabel : ''} onChange={e => handleHighlightedBarLegendLabel(e, i)} />
3235
+ <input
3236
+ type='text'
3237
+ value={
3238
+ config.highlightedBarValues[i].legendLabel
3239
+ ? config.highlightedBarValues[i].legendLabel
3240
+ : ''
3241
+ }
3242
+ onChange={e => handleHighlightedBarLegendLabel(e, i)}
3243
+ />
2211
3244
  </label>
2212
3245
  </div>
2213
3246
  </fieldset>
@@ -2231,10 +3264,15 @@ const EditorPanel = () => {
2231
3264
  tooltip={
2232
3265
  <Tooltip style={{ textTransform: 'none' }}>
2233
3266
  <Tooltip.Target>
2234
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
3267
+ <Icon
3268
+ display='question'
3269
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
3270
+ />
2235
3271
  </Tooltip.Target>
2236
3272
  <Tooltip.Content>
2237
- <p>When this option is checked, you can select values for exclusion from the pie segments.</p>
3273
+ <p>
3274
+ When this option is checked, you can select values for exclusion from the pie segments.
3275
+ </p>
2238
3276
  </Tooltip.Content>
2239
3277
  </Tooltip>
2240
3278
  }
@@ -2399,7 +3437,10 @@ const EditorPanel = () => {
2399
3437
  <span className='edit-label column-heading'>Anchors</span>
2400
3438
  <Accordion allowZeroExpanded>
2401
3439
  {config.yAxis?.anchors?.map((anchor, index) => (
2402
- <AccordionItem className='series-item series-item--chart' key={`accordion-yaxis-anchors-${index}`}>
3440
+ <AccordionItem
3441
+ className='series-item series-item--chart'
3442
+ key={`accordion-yaxis-anchors-${index}`}
3443
+ >
2403
3444
  <AccordionItemHeading className='series-item__title'>
2404
3445
  <>
2405
3446
  <AccordionItemButton className={'accordion__button accordion__button'}>
@@ -2542,7 +3583,69 @@ const EditorPanel = () => {
2542
3583
  <AccordionItemButton>Legend</AccordionItemButton>
2543
3584
  </AccordionItemHeading>
2544
3585
  <AccordionItemPanel>
2545
- <CheckBox value={config.legend.reverseLabelOrder} section='legend' fieldName='reverseLabelOrder' label='Reverse Labels' updateField={updateField} />
3586
+ <Select
3587
+ value={config.legend?.position}
3588
+ section='legend'
3589
+ fieldName='position'
3590
+ label='Position'
3591
+ updateField={updateField}
3592
+ options={['right', 'left', 'bottom', 'top']}
3593
+ />
3594
+ {(config.legend.position === 'left' ||
3595
+ config.legend.position === 'right' ||
3596
+ !config.legend.position) &&
3597
+ config.legend.style === 'gradient' && (
3598
+ <span style={{ color: 'red', fontSize: '14px' }}>
3599
+ Position must be set to top or bottom to use gradient style.
3600
+ </span>
3601
+ )}
3602
+
3603
+ <Select
3604
+ tooltip={
3605
+ <Tooltip style={{ textTransform: 'none' }}>
3606
+ <Tooltip.Target>
3607
+ <Icon
3608
+ display='question'
3609
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
3610
+ />
3611
+ </Tooltip.Target>
3612
+ <Tooltip.Content>
3613
+ <p>
3614
+ If using gradient style, limit the legend to five items for better mobile visibility, and
3615
+ position the legend at the top or bottom.
3616
+ </p>
3617
+ </Tooltip.Content>
3618
+ </Tooltip>
3619
+ }
3620
+ display={!config.legend.hide}
3621
+ value={config.legend.style}
3622
+ section='legend'
3623
+ fieldName='style'
3624
+ label='Legend Style'
3625
+ updateField={updateField}
3626
+ options={getLegendStyleOptions('style')}
3627
+ />
3628
+
3629
+ <Select
3630
+ display={!config.legend.hide && config.legend.style === 'gradient'}
3631
+ value={config.legend.subStyle}
3632
+ section='legend'
3633
+ fieldName='subStyle'
3634
+ label='Gradient Style'
3635
+ updateField={updateField}
3636
+ options={getLegendStyleOptions('subStyle')}
3637
+ />
3638
+ <TextField
3639
+ display={config.legend.style === 'gradient' && !config.legend.hide}
3640
+ className='number-narrow'
3641
+ type='number'
3642
+ value={config.legend.tickRotation}
3643
+ section='legend'
3644
+ fieldName='tickRotation'
3645
+ label='Tick Rotation (Degrees)'
3646
+ updateField={updateField}
3647
+ />
3648
+
2546
3649
  {/* <fieldset className="checkbox-group">
2547
3650
  <CheckBox value={config.legend.dynamicLegend} section="legend" fieldName="dynamicLegend" label="Dynamic Legend" updateField={updateField}/>
2548
3651
  {config.legend.dynamicLegend && (
@@ -2554,6 +3657,7 @@ const EditorPanel = () => {
2554
3657
  </>
2555
3658
  )}
2556
3659
  </fieldset> */}
3660
+
2557
3661
  <CheckBox
2558
3662
  value={config.legend.hide ? true : false}
2559
3663
  section='legend'
@@ -2563,7 +3667,10 @@ const EditorPanel = () => {
2563
3667
  tooltip={
2564
3668
  <Tooltip style={{ textTransform: 'none' }}>
2565
3669
  <Tooltip.Target>
2566
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
3670
+ <Icon
3671
+ display='question'
3672
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
3673
+ />
2567
3674
  </Tooltip.Target>
2568
3675
  <Tooltip.Content>
2569
3676
  <p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
@@ -2572,6 +3679,7 @@ const EditorPanel = () => {
2572
3679
  }
2573
3680
  />
2574
3681
  <CheckBox
3682
+ display={config.preliminaryData?.some(pd => pd.label && pd.type === 'suppression' && pd.value)}
2575
3683
  value={config.legend.hideSuppressedLabels}
2576
3684
  section='legend'
2577
3685
  fieldName='hideSuppressedLabels'
@@ -2580,10 +3688,37 @@ const EditorPanel = () => {
2580
3688
  tooltip={
2581
3689
  <Tooltip style={{ textTransform: 'none' }}>
2582
3690
  <Tooltip.Target>
2583
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
3691
+ <Icon
3692
+ display='question'
3693
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
3694
+ />
3695
+ </Tooltip.Target>
3696
+ <Tooltip.Content>
3697
+ <p>
3698
+ Hiding suppressed labels will not override the 'Special Class' assigned to line chart
3699
+ indicating "suppressed" data in the Data Series Panel.
3700
+ </p>
3701
+ </Tooltip.Content>
3702
+ </Tooltip>
3703
+ }
3704
+ />
3705
+ <CheckBox
3706
+ display={config.preliminaryData?.some(pd => pd.label && pd.type === 'suppression' && pd.value)}
3707
+ value={config.legend.hideSuppressionLink}
3708
+ section='legend'
3709
+ fieldName='hideSuppressionLink'
3710
+ label='Hide Suppression Definition Link'
3711
+ updateField={updateField}
3712
+ tooltip={
3713
+ <Tooltip style={{ textTransform: 'none' }}>
3714
+ <Tooltip.Target>
3715
+ <Icon
3716
+ display='question'
3717
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
3718
+ />
2584
3719
  </Tooltip.Target>
2585
3720
  <Tooltip.Content>
2586
- <p>Hiding suppressed labels will not override the 'Special Class' assigned to line chart indicating "suppressed" data in the Data Series Panel.</p>
3721
+ <p>Selecting this option will hide the suppression definition link from display.</p>
2587
3722
  </Tooltip.Content>
2588
3723
  </Tooltip>
2589
3724
  }
@@ -2594,15 +3729,43 @@ const EditorPanel = () => {
2594
3729
  <TextField type='textarea' value={config.boxplot.legend.howToReadText} updateField={updateField} fieldName='howToReadText' section='boxplot' subsection='legend' label='How to read text' />
2595
3730
  </>
2596
3731
  } */}
2597
- {config.visualizationType === 'Line' && <CheckBox value={config.legend.lineMode} section='legend' fieldName='lineMode' label='Show Lined Style Legend' updateField={updateField} />}
2598
- {config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1 && (
2599
- <Select value={config.legend.colorCode} section='legend' fieldName='colorCode' label='Color code by category' initial='Select' updateField={updateField} options={getDataValueOptions(data)} />
3732
+ <Select
3733
+ display={config.series?.length > 1}
3734
+ value={config.legend.behavior}
3735
+ section='legend'
3736
+ fieldName='behavior'
3737
+ label='Legend Behavior (When clicked)'
3738
+ updateField={(...[section, , fieldName, value]) => updateBehavior(section, fieldName, value)}
3739
+ options={['highlight', 'isolate']}
3740
+ />
3741
+ <Select
3742
+ display={visHasLegendColorCategory()}
3743
+ value={config.legend.colorCode}
3744
+ section='legend'
3745
+ fieldName='colorCode'
3746
+ label='Color code by category'
3747
+ initial='Select'
3748
+ updateField={updateField}
3749
+ options={getDataValueOptions(data)}
3750
+ />
3751
+ {visHasLegendAxisAlign() && (
3752
+ <CheckBox
3753
+ value={config.legend.axisAlign}
3754
+ fieldName='axisAlign'
3755
+ section='legend'
3756
+ label='Align to Axis on Isolate'
3757
+ updateField={updateField}
3758
+ />
3759
+ )}
3760
+ {config.legend.behavior === 'highlight' && config.tooltips.singleSeries && (
3761
+ <CheckBox
3762
+ value={config.legend.highlightOnHover}
3763
+ section='legend'
3764
+ fieldName='highlightOnHover'
3765
+ label='HIGHLIGHT DATA SERIES ON HOVER'
3766
+ updateField={updateField}
3767
+ />
2600
3768
  )}
2601
- <Select value={config.legend.behavior} section='legend' fieldName='behavior' label='Legend Behavior (When clicked)' updateField={(...[section, , fieldName, value]) => updateBehavior(section, fieldName, value)} options={['highlight', 'isolate']} />
2602
- {visHasLegendAxisAlign() && <CheckBox value={config.legend.axisAlign} fieldName='axisAlign' section='legend' label='Align to Axis on Isolate' updateField={updateField} />}
2603
-
2604
- {config.legend.behavior === 'highlight' && config.tooltips.singleSeries && <CheckBox value={config.legend.highlightOnHover} section='legend' fieldName='highlightOnHover' label='HIGHLIGHT DATA SERIES ON HOVER' updateField={updateField} />}
2605
-
2606
3769
  {/* start: isolated values */}
2607
3770
  {visHasSelectableLegendValues && config.legend.behavior === 'isolate' && !colorCodeByCategory && (
2608
3771
  <fieldset className='primary-fieldset edit-block' key={'additional-highlight-values'}>
@@ -2614,7 +3777,10 @@ const EditorPanel = () => {
2614
3777
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2615
3778
  </Tooltip.Target>
2616
3779
  <Tooltip.Content>
2617
- <p>You can choose data series that are shown on load. Others will be added when the user clicks on them in the legend.</p>
3780
+ <p>
3781
+ You can choose data series that are shown on load. Others will be added when the user
3782
+ clicks on them in the legend.
3783
+ </p>
2618
3784
  </Tooltip.Content>
2619
3785
  </Tooltip>
2620
3786
  </span>
@@ -2670,16 +3836,99 @@ const EditorPanel = () => {
2670
3836
  </fieldset>
2671
3837
  )}
2672
3838
  {/* end: isolated values */}
2673
-
2674
- <TextField value={config.legend.label} section='legend' fieldName='label' label='Title' updateField={updateField} />
2675
- <Select value={config.legend?.position} section='legend' fieldName='position' label='Position' updateField={updateField} options={['right', 'left', 'bottom']} />
2676
- {config.legend.position === 'bottom' && (
2677
- <>
2678
- <CheckBox value={config.legend.singleRow} section='legend' fieldName='singleRow' label='Single Row Legend' updateField={updateField} />
2679
- <CheckBox value={config.legend.verticalSorted} section='legend' fieldName='verticalSorted' label='Vertical sorted Legend' updateField={updateField} />
2680
- </>
2681
- )}
2682
- <TextField type='textarea' value={config.legend.description} updateField={updateField} section='legend' fieldName='description' label='Legend Description' />
3839
+ <CheckBox
3840
+ display={!config.legend.hide && config.legend.style !== 'gradient'}
3841
+ value={config.legend.reverseLabelOrder}
3842
+ section='legend'
3843
+ fieldName='reverseLabelOrder'
3844
+ label='Reverse Labels'
3845
+ updateField={updateField}
3846
+ />
3847
+ <CheckBox
3848
+ display={!config.legend.hide}
3849
+ value={
3850
+ ['left', 'right'].includes(config.legend.position)
3851
+ ? config.legend.hideBorder.side
3852
+ : config.legend.hideBorder.topBottom
3853
+ }
3854
+ section='legend'
3855
+ subsection='hideBorder'
3856
+ fieldName={['left', 'right'].includes(config.legend.position) ? 'side' : 'topBottom'}
3857
+ label='Hide Legend Box'
3858
+ updateField={updateField}
3859
+ tooltip={
3860
+ <Tooltip style={{ textTransform: 'none' }}>
3861
+ <Tooltip.Target>
3862
+ <Icon
3863
+ display='question'
3864
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
3865
+ />
3866
+ </Tooltip.Target>
3867
+ <Tooltip.Content>
3868
+ <p>Default option for top and bottom legends is ‘No Box.’.</p>
3869
+ </Tooltip.Content>
3870
+ </Tooltip>
3871
+ }
3872
+ />
3873
+ <CheckBox
3874
+ display={
3875
+ !config.legend.hide &&
3876
+ !['left', 'right'].includes(config.legend.position) &&
3877
+ config.legend.style !== 'gradient'
3878
+ }
3879
+ value={config.legend.singleRow}
3880
+ section='legend'
3881
+ fieldName='singleRow'
3882
+ label='Single Row Legend'
3883
+ updateField={updateField}
3884
+ />
3885
+ <CheckBox
3886
+ display={
3887
+ ['bottom', 'top'].includes(config.legend.position) &&
3888
+ !config.legend.hide &&
3889
+ config.legend.style !== 'gradient'
3890
+ }
3891
+ value={config.legend.verticalSorted}
3892
+ section='legend'
3893
+ fieldName='verticalSorted'
3894
+ label='Vertical sorted Legend'
3895
+ updateField={updateField}
3896
+ />
3897
+ <CheckBox
3898
+ value={config.legend.hide ? true : false}
3899
+ section='legend'
3900
+ fieldName='hide'
3901
+ label='Hide Legend'
3902
+ updateField={updateField}
3903
+ tooltip={
3904
+ <Tooltip style={{ textTransform: 'none' }}>
3905
+ <Tooltip.Target>
3906
+ <Icon
3907
+ display='question'
3908
+ style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }}
3909
+ />
3910
+ </Tooltip.Target>
3911
+ <Tooltip.Content>
3912
+ <p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
3913
+ </Tooltip.Content>
3914
+ </Tooltip>
3915
+ }
3916
+ />
3917
+ <TextField
3918
+ value={config.legend.label}
3919
+ section='legend'
3920
+ fieldName='label'
3921
+ label='Title'
3922
+ updateField={updateField}
3923
+ />
3924
+ <TextField
3925
+ type='textarea'
3926
+ value={config.legend.description}
3927
+ updateField={updateField}
3928
+ section='legend'
3929
+ fieldName='description'
3930
+ label='Legend Description'
3931
+ />
2683
3932
  </AccordionItemPanel>
2684
3933
  </AccordionItem>
2685
3934
  )}
@@ -2701,14 +3950,22 @@ const EditorPanel = () => {
2701
3950
  <AccordionItemButton>Data Table</AccordionItemButton>
2702
3951
  </AccordionItemHeading>
2703
3952
  <AccordionItemPanel>
2704
- <DataTableEditor config={config} columns={Object.keys(data[0] || {})} updateField={updateField} isDashboard={isDashboard} isLoadedFromUrl={isLoadedFromUrl} />{' '}
3953
+ <DataTableEditor
3954
+ config={config}
3955
+ columns={Object.keys(data[0] || {})}
3956
+ updateField={updateField}
3957
+ isDashboard={isDashboard}
3958
+ isLoadedFromUrl={isLoadedFromUrl}
3959
+ />{' '}
2705
3960
  </AccordionItemPanel>
2706
3961
  </AccordionItem>
2707
3962
  )}
2708
3963
  <Panels.Annotate name='Text Annotations' />
2709
3964
  {/* {(config.visualizationType === 'Bar' || config.visualizationType === 'Line') && <Panels.DateHighlighting name='Date Highlighting' />} */}
2710
3965
  </Accordion>
2711
- {config.type !== 'Spark Line' && <AdvancedEditor loadConfig={updateConfig} config={config} convertStateToConfig={convertStateToConfig} />}
3966
+ {config.type !== 'Spark Line' && (
3967
+ <AdvancedEditor loadConfig={updateConfig} config={config} convertStateToConfig={convertStateToConfig} />
3968
+ )}
2712
3969
  </Layout.Sidebar>
2713
3970
  </ErrorBoundary>
2714
3971
  </EditorPanelContext.Provider>