@cdc/chart 4.22.11 → 4.23.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/dist/495.js +3 -0
  2. package/dist/703.js +1 -0
  3. package/dist/cdcchart.js +723 -6
  4. package/examples/box-plot-data.json +71 -0
  5. package/examples/box-plot.csv +5 -0
  6. package/examples/{private/yaxis-test.json → box-plot.json} +47 -56
  7. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +3 -1
  8. package/examples/gallery/bar-chart-vertical/vertical-bar-chart.json +85 -16
  9. package/examples/new-data.csv +17 -0
  10. package/examples/newdata.json +90 -0
  11. package/package.json +3 -2
  12. package/src/CdcChart.tsx +150 -94
  13. package/src/components/BarChart.tsx +156 -226
  14. package/src/components/BoxPlot.js +92 -0
  15. package/src/components/DataTable.tsx +28 -12
  16. package/src/components/EditorPanel.js +151 -104
  17. package/src/components/Filters.js +131 -0
  18. package/src/components/Legend.js +8 -1
  19. package/src/components/LineChart.tsx +64 -13
  20. package/src/components/LinearChart.tsx +120 -81
  21. package/src/components/PairedBarChart.tsx +1 -1
  22. package/src/components/PieChart.tsx +12 -2
  23. package/src/components/useIntersectionObserver.tsx +9 -7
  24. package/src/data/initial-state.js +14 -8
  25. package/src/hooks/useReduceData.ts +8 -5
  26. package/src/index.html +51 -51
  27. package/src/scss/DataTable.scss +1 -1
  28. package/src/scss/main.scss +53 -22
  29. package/examples/private/filters.json +0 -170
  30. package/examples/private/line-test-data.json +0 -22
  31. package/examples/private/line-test-two.json +0 -210
  32. package/examples/private/line-test.json +0 -102
  33. package/examples/private/new.json +0 -48800
  34. package/examples/private/newtest.csv +0 -101
  35. package/examples/private/shawn.json +0 -1106
  36. package/examples/private/test.json +0 -10124
  37. package/examples/private/yaxis-testing.csv +0 -27
  38. package/examples/private/yaxis.json +0 -28
@@ -8,16 +8,19 @@ import LegendCircle from '@cdc/core/components/LegendCircle'
8
8
 
9
9
  import Context from '../context'
10
10
 
11
+ import CoveMediaControls from '@cdc/core/helpers/CoveMediaControls'
12
+
11
13
  export default function DataTable() {
12
- const { rawData, transformedData: data, config, colorScale, parseDate, formatDate, formatNumber: numberFormatter, colorPalettes } = useContext<any>(Context)
14
+ const { rawData, transformedData: data, config, colorScale, parseDate, formatDate, formatNumber: numberFormatter, colorPalettes, imageId } = useContext<any>(Context)
15
+
16
+ // Debugging.
17
+ // if (config.visualizationType === 'Box Plot') return null
13
18
 
14
- const legendGlyphSize = 15
15
- const legendGlyphSizeHalf = legendGlyphSize / 2
16
19
  const section = config.orientation === 'horizontal' ? 'yAxis' : 'xAxis'
17
20
  const [tableExpanded, setTableExpanded] = useState<boolean>(config.table.expanded)
18
21
  const [accessibilityLabel, setAccessibilityLabel] = useState('')
19
22
 
20
- const DownloadButton = ({ data }: any) => {
23
+ const DownloadButton = ({ data }: any, type) => {
21
24
  const fileName = `${config.title.substring(0, 50)}.csv`
22
25
 
23
26
  const csvData = Papa.unparse(data)
@@ -31,11 +34,20 @@ export default function DataTable() {
31
34
  }
32
35
  }
33
36
 
34
- return (
35
- <a download={fileName} onClick={saveBlob} href={`data:text/csv;base64,${Base64.encode(csvData)}`} aria-label='Download this data in a CSV file format.' className={`btn btn-download no-border`}>
36
- Download Data (CSV)
37
- </a>
38
- )
37
+ switch (type) {
38
+ case 'download':
39
+ return (
40
+ <a download={fileName} onClick={saveBlob} href={`data:text/csv;base64,${Base64.encode(csvData)}`} aria-label='Download this data in a CSV file format.' className={`btn btn-download no-border`}>
41
+ Download Data (CSV)
42
+ </a>
43
+ )
44
+ default:
45
+ return (
46
+ <a download={fileName} onClick={saveBlob} href={`data:text/csv;base64,${Base64.encode(csvData)}`} aria-label='Download this data in a CSV file format.' className={`no-border`}>
47
+ Download Data (CSV)
48
+ </a>
49
+ )
50
+ }
39
51
  }
40
52
 
41
53
  // Creates columns structure for the table
@@ -72,13 +84,13 @@ export default function DataTable() {
72
84
  }
73
85
  ]
74
86
 
75
- data.forEach(d => {
87
+ data.forEach((d, index) => {
76
88
  const newCol = {
77
89
  Header: config.runtime[section].type === 'date' ? formatDate(parseDate(d[config.runtime.originalXAxis.dataKey])) : d[config.runtime.originalXAxis.dataKey],
78
90
  Cell: ({ row }) => {
79
91
  return <>{numberFormatter(d[row.original])}</>
80
92
  },
81
- id: d[config.runtime.originalXAxis.dataKey],
93
+ id: `${d[config.runtime.originalXAxis.dataKey]}--${index}`,
82
94
  canSort: true
83
95
  }
84
96
 
@@ -117,6 +129,11 @@ export default function DataTable() {
117
129
  const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable({ columns: tableColumns, data: tableData, defaultColumn }, useSortBy, useBlockLayout, useResizeColumns)
118
130
  return (
119
131
  <ErrorBoundary component='DataTable'>
132
+ <CoveMediaControls.Section classes={['download-links']}>
133
+ <CoveMediaControls.Link config={config} />
134
+ {config.table.download && <DownloadButton data={rawData} type='link' />}
135
+ </CoveMediaControls.Section>
136
+
120
137
  <section id={config?.title ? `dataTableSection__${config?.title.replace(/\s/g, '')}` : `dataTableSection`} className={`data-table-container`} aria-label={accessibilityLabel}>
121
138
  <div
122
139
  role='button'
@@ -206,7 +223,6 @@ export default function DataTable() {
206
223
  ''
207
224
  )}
208
225
  </div>
209
- {config.table.download && <DownloadButton data={rawData} />}
210
226
  </section>
211
227
  </ErrorBoundary>
212
228
  )
@@ -3,19 +3,15 @@ import { DragDropContext, Droppable, Draggable } from 'react-beautiful-dnd'
3
3
 
4
4
  import { Accordion, AccordionItem, AccordionItemHeading, AccordionItemPanel, AccordionItemButton } from 'react-accessible-accordion'
5
5
 
6
- import { timeParse, timeFormat } from 'd3-time-format'
7
- import { useDebounce, useDebouncedCallback } from 'use-debounce'
6
+ import { useDebounce } from 'use-debounce'
8
7
 
9
8
  import Context from '../context'
10
9
  import WarningImage from '../images/warning.svg'
11
10
  import AdvancedEditor from '@cdc/core/components/AdvancedEditor'
12
11
 
13
12
  import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
14
- import Waiting from '@cdc/core/components/Waiting'
15
- import QuestionIcon from '@cdc/core/assets/icon-question-circle.svg' //TODO: Update with Icon component
16
13
  import { useColorPalette } from '../hooks/useColorPalette'
17
14
 
18
- import InputCheckbox from '@cdc/core/components/inputs/InputCheckbox'
19
15
  import InputToggle from '@cdc/core/components/inputs/InputToggle'
20
16
  import Tooltip from '@cdc/core/components/ui/Tooltip'
21
17
  import Icon from '@cdc/core/components/ui/Icon'
@@ -25,6 +21,8 @@ import useRightAxis from '../hooks/useRightAxis'
25
21
  // TODO: Remove unused imports
26
22
  // TDOO: Move inline styles to a scss file
27
23
 
24
+ /* eslint-disable react-hooks/rules-of-hooks */
25
+
28
26
  const TextField = memo(({ label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = 'input', i = null, min = null, ...attributes }) => {
29
27
  const [value, setValue] = useState(stateValue)
30
28
 
@@ -34,7 +32,7 @@ const TextField = memo(({ label, tooltip, section = null, subsection = null, fie
34
32
  if ('string' === typeof debouncedValue && stateValue !== debouncedValue) {
35
33
  updateField(section, subsection, fieldName, debouncedValue, i)
36
34
  }
37
- }, [debouncedValue])
35
+ }, [debouncedValue]) // eslint-disable-line
38
36
 
39
37
  let name = subsection ? `${section}-${subsection}-${fieldName}` : `${section}-${subsection}-${fieldName}`
40
38
 
@@ -211,17 +209,17 @@ const Regions = memo(({ config, updateConfig }) => {
211
209
  const headerColors = ['theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber']
212
210
 
213
211
  const EditorPanel = () => {
214
- const { config, updateConfig, transformedData: data, loading, colorPalettes, unfilteredData, excludedData, transformedData, isDashboard, setParentConfig, missingRequiredSections, setFilteredData } = useContext(Context)
212
+ const { config, updateConfig, transformedData: data, loading, colorPalettes, unfilteredData, excludedData, isDashboard, setParentConfig, missingRequiredSections } = useContext(Context)
215
213
 
216
- const { minValue, maxValue, existPositiveValue } = useReduceData(config, unfilteredData)
214
+ const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
217
215
  const { paletteName, isPaletteReversed, filteredPallets, filteredQualitative, dispatch } = useColorPalette(colorPalettes, config)
218
216
  useEffect(() => {
219
217
  if (paletteName) updateConfig({ ...config, palette: paletteName })
220
- }, [paletteName])
218
+ }, [paletteName]) // eslint-disable-line
221
219
 
222
220
  useEffect(() => {
223
221
  dispatch({ type: 'GET_PALETTE', payload: colorPalettes, paletteName: config.palette })
224
- }, [dispatch, config.palette])
222
+ }, [dispatch, config.palette]) // eslint-disable-line
225
223
 
226
224
  // when the visualization type changes we
227
225
  // have to update the individual series type & axis details
@@ -243,7 +241,7 @@ const EditorPanel = () => {
243
241
  ...config,
244
242
  series: newSeries
245
243
  })
246
- }, [config.visualizationType])
244
+ }, [config.visualizationType]) // eslint-disable-line
247
245
 
248
246
  const { hasRightAxis } = useRightAxis({ config: config, yMax: config.yAxis.size, data: config.data, updateConfig })
249
247
 
@@ -325,7 +323,6 @@ const EditorPanel = () => {
325
323
  }
326
324
 
327
325
  const [displayPanel, setDisplayPanel] = useState(true)
328
- const [lollipopColorStyle, setLollipopColorStyle] = useState('two-tone')
329
326
 
330
327
  if (loading) {
331
328
  return null
@@ -442,14 +439,11 @@ const EditorPanel = () => {
442
439
  const getColumns = (filter = true) => {
443
440
  let columns = {}
444
441
 
445
- unfilteredData.map(row => {
442
+ unfilteredData.forEach(row => {
446
443
  Object.keys(row).forEach(columnName => (columns[columnName] = true))
447
444
  })
448
445
 
449
446
  if (filter) {
450
- let confidenceUpper = config.confidenceKeys?.upper && config.confidenceKeys?.upper !== '' // TODO: remove?
451
- let confidenceLower = config.confidenceKeys?.lower && config.confidenceKeys?.lower !== '' // TODO: remove?
452
-
453
447
  Object.keys(columns).forEach(key => {
454
448
  if (
455
449
  (config.series && config.series.filter(series => series.dataKey === key).length > 0) ||
@@ -471,7 +465,7 @@ const EditorPanel = () => {
471
465
  if (!data) return []
472
466
  const set = new Set()
473
467
  for (let i = 0; i < data.length; i++) {
474
- for (const [key, value] of Object.entries(data[i])) {
468
+ for (const [key] of Object.entries(data[i])) {
475
469
  set.add(key)
476
470
  }
477
471
  }
@@ -480,7 +474,7 @@ const EditorPanel = () => {
480
474
 
481
475
  const getDataValues = (dataKey, unique = false) => {
482
476
  let values = []
483
- excludedData.map(e => {
477
+ excludedData.forEach(e => {
484
478
  values.push(e[dataKey])
485
479
  })
486
480
  return unique ? [...new Set(values)] : values
@@ -560,7 +554,7 @@ const EditorPanel = () => {
560
554
  orientation: 'horizontal'
561
555
  })
562
556
  }
563
- }, [])
557
+ }, []) // eslint-disable-line
564
558
 
565
559
  useEffect(() => {
566
560
  if (config.orientation === 'horizontal') {
@@ -569,7 +563,7 @@ const EditorPanel = () => {
569
563
  lollipopShape: config.lollipopShape
570
564
  })
571
565
  }
572
- }, [config.isLollipopChart, config.lollipopShape])
566
+ }, [config.isLollipopChart, config.lollipopShape]) // eslint-disable-line
573
567
 
574
568
  const ExclusionsList = useCallback(() => {
575
569
  const exclusions = [...config.exclusions.keys]
@@ -589,18 +583,7 @@ const EditorPanel = () => {
589
583
  })}
590
584
  </ul>
591
585
  )
592
- }, [config])
593
-
594
- const ErrorWithLolliopChart = ({ message }) => {
595
- return (
596
- <section className='waiting'>
597
- <section className='waiting-container'>
598
- <h3>Error With Configuration</h3>
599
- <p>{message}</p>
600
- </section>
601
- </section>
602
- )
603
- }
586
+ }, [config]) // eslint-disable-line
604
587
 
605
588
  const checkIsLine = type => {
606
589
  return type === ('Line' || 'dashed-sm')
@@ -616,7 +599,14 @@ const EditorPanel = () => {
616
599
  filterItem.orderedValues = filterOrder
617
600
  filterItem.order = 'cust'
618
601
  filters[filterIndex] = filterItem
619
- updateConfig({ ...config, filters });
602
+ updateConfig({ ...config, filters })
603
+ }
604
+
605
+ const handleSeriesChange = (idx1, idx2) => {
606
+ let seriesOrder = config.series
607
+ let [movedItem] = seriesOrder.splice(idx1, 1)
608
+ seriesOrder.splice(idx2, 0, movedItem)
609
+ updateConfig({ ...config, series: seriesOrder })
620
610
  }
621
611
 
622
612
  if (config.isLollipopChart && config?.series?.length > 1) {
@@ -658,7 +648,10 @@ const EditorPanel = () => {
658
648
  case (config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && enteredValue && parseFloat(enteredValue) > minVal:
659
649
  message = 'Value must be less than ' + minValue
660
650
  break
661
- case (config.visualizationType === 'Bar' || config.visualizationType === 'Combo') && enteredValue && minVal > 0 && parseFloat(enteredValue) > 0:
651
+ case config.visualizationType === 'Combo' && isAllLine && enteredValue && parseFloat(enteredValue) > minVal:
652
+ message = 'Value must be less than ' + minValue
653
+ break
654
+ case (config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && enteredValue && minVal > 0 && parseFloat(enteredValue) > 0:
662
655
  message = 'Value must be less than or equal to 0'
663
656
  break
664
657
  case enteredValue && minVal < 0 && parseFloat(enteredValue) > minVal:
@@ -671,11 +664,10 @@ const EditorPanel = () => {
671
664
  return { ...prevMsg, minMsg: message }
672
665
  })
673
666
  }
674
-
675
667
  useEffect(() => {
676
668
  validateMinValue()
677
669
  validateMaxValue()
678
- }, [minValue, maxValue, config])
670
+ }, [minValue, maxValue, config]) // eslint-disable-line
679
671
 
680
672
  return (
681
673
  <ErrorBoundary component='EditorPanel'>
@@ -709,8 +701,8 @@ const EditorPanel = () => {
709
701
  config.visualizationType !== 'Pie' && <CheckBox value={config.labels} fieldName='labels' label='Display label on data' updateField={updateField} />
710
702
  )}
711
703
  {config.visualizationType === 'Pie' && <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />}
712
- <TextField value={config.title} fieldName='title' label='Title' updateField={updateField} />
713
704
 
705
+ <TextField value={config.title} fieldName='title' label='Title' updateField={updateField} />
714
706
  <TextField
715
707
  value={config.superTitle}
716
708
  updateField={updateField}
@@ -783,7 +775,7 @@ const EditorPanel = () => {
783
775
  }
784
776
  />
785
777
 
786
- {config.visualizationSubType !== 'horizontal' && <TextField type='number' value={config.height} fieldName='height' label='Chart Height' updateField={updateField} />}
778
+ {config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
787
779
  </AccordionItemPanel>
788
780
  </AccordionItem>
789
781
 
@@ -808,69 +800,95 @@ const EditorPanel = () => {
808
800
  </Tooltip.Content>
809
801
  </Tooltip>
810
802
  </fieldset>
811
- <ul className='series-list'>
812
- {config.series &&
813
- config.series.map((series, i) => {
814
- if (config.visualizationType === 'Combo') {
815
- let changeType = (i, value) => {
816
- let series = [...config.series]
817
- series[i].type = value
818
-
819
- series[i].axis = 'Left'
820
-
821
- updateConfig({ ...config, series })
822
- }
823
-
824
- let typeDropdown = (
825
- <select
826
- value={series.type}
827
- onChange={event => {
828
- changeType(i, event.target.value)
829
- }}
830
- style={{ width: '100px', marginRight: '10px' }}
831
- >
832
- <option value='' default>
833
- Select
834
- </option>
835
- <option value='Bar'>Bar</option>
836
- <option value='Line'>Solid Line</option>
837
- <option value='dashed-sm'>Small Dashed</option>
838
- <option value='dashed-md'>Medium Dashed</option>
839
- <option value='dashed-lg'>Large Dashed</option>
840
- </select>
841
- )
842
803
 
843
- return (
844
- <li key={series.dataKey}>
845
- <div className={`series-list__name${series.dataKey.length > 15 ? ' series-list__name--truncate' : ''}`} data-title={series.dataKey}>
846
- <div className='series-list__name-text'>{series.dataKey}</div>
847
- </div>
848
- <span>
849
- <span className='series-list__dropdown'>{typeDropdown}</span>
850
- {config.series && config.series.length > 1 && (
851
- <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
852
- &#215;
853
- </button>
854
- )}
855
- </span>
856
- </li>
857
- )
858
- }
804
+ <DragDropContext onDragEnd={({ source, destination }) => handleSeriesChange(source.index, destination.index)}>
805
+ <Droppable droppableId='filter_order'>
806
+ {provided => (
807
+ <ul {...provided.droppableProps} className='series-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
808
+ {config.series.map((series, i) => {
809
+ if (config.visualizationType === 'Combo') {
810
+ let changeType = (i, value) => {
811
+ let series = [...config.series]
812
+ series[i].type = value
813
+
814
+ series[i].axis = 'Left'
815
+
816
+ updateConfig({ ...config, series })
817
+ }
818
+
819
+ let typeDropdown = (
820
+ <select
821
+ value={series.type}
822
+ onChange={event => {
823
+ changeType(i, event.target.value)
824
+ }}
825
+ style={{ width: '100px', marginRight: '10px' }}
826
+ >
827
+ <option value='' default>
828
+ Select
829
+ </option>
830
+ <option value='Bar'>Bar</option>
831
+ <option value='Line'>Solid Line</option>
832
+ <option value='dashed-sm'>Small Dashed</option>
833
+ <option value='dashed-md'>Medium Dashed</option>
834
+ <option value='dashed-lg'>Large Dashed</option>
835
+ </select>
836
+ )
837
+
838
+ return (
839
+ <Draggable key={series.dataKey} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
840
+ {(provided, snapshot) => (
841
+ <li>
842
+ <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
843
+ <div className={`series-list__name${series.dataKey.length > 15 ? ' series-list__name--truncate' : ''}`} data-title={series.dataKey}>
844
+ <div className='series-list__name-text'>{series.dataKey}</div>
845
+ </div>
846
+ <span>
847
+ <span className='series-list__dropdown'>{typeDropdown}</span>
848
+ {config.series && config.series.length > 1 && (
849
+ <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
850
+ &#215;
851
+ </button>
852
+ )}
853
+ </span>
854
+ </div>
855
+ </li>
856
+ )}
857
+ </Draggable>
858
+ )
859
+ }
859
860
 
860
- return (
861
- <li key={series.dataKey}>
862
- <div className='series-list__name' data-title={series.dataKey}>
863
- <div className='series-list__name--text'>{series.dataKey}</div>
864
- </div>
865
- {config.series && config.series.length > 1 && (
866
- <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
867
- &#215;
868
- </button>
869
- )}
870
- </li>
871
- )
872
- })}
873
- </ul>
861
+ return (
862
+ <Draggable key={series.dataKey} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
863
+ {(provided, snapshot) => (
864
+ <li
865
+ key={series.dataKey}
866
+ className={snapshot.isDragging ? 'currently-dragging' : ''}
867
+ style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)}
868
+ ref={provided.innerRef}
869
+ {...provided.draggableProps}
870
+ {...provided.dragHandleProps}
871
+ >
872
+ {/*<div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>*/}
873
+ <div className='series-list__name' data-title={series.dataKey}>
874
+ <div className='series-list__name--text'>{series.dataKey}</div>
875
+ </div>
876
+ {config.series && config.series.length > 1 && (
877
+ <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
878
+ &#215;
879
+ </button>
880
+ )}
881
+ {/*</div>*/}
882
+ </li>
883
+ )}
884
+ </Draggable>
885
+ )
886
+ })}
887
+ {provided.placeholder}
888
+ </ul>
889
+ )}
890
+ </Droppable>
891
+ </DragDropContext>
874
892
  </>
875
893
  )}
876
894
 
@@ -966,7 +984,7 @@ const EditorPanel = () => {
966
984
  <AccordionItem>
967
985
  <AccordionItemHeading>
968
986
  <AccordionItemButton>
969
- {config.visualizationType !== 'Pie' ? (config.visualizationType === 'Bar' ? 'Left Value Axis' : 'Left Value Axis') : 'Data Format'}
987
+ {config.visualizationType !== 'Pie' ? (config.orientation !== 'horizontal' ? 'Left Value Axis' : 'Value Axis') : 'Data Format'}
970
988
  {config.visualizationType === 'Pie' && !config.yAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
971
989
  </AccordionItemButton>
972
990
  </AccordionItemHeading>
@@ -996,7 +1014,7 @@ const EditorPanel = () => {
996
1014
  {config.visualizationType !== 'Pie' && (
997
1015
  <>
998
1016
  <TextField value={config.yAxis.label} section='yAxis' fieldName='label' label='Label' updateField={updateField} />
999
- <CheckBox value={config.yAxis.isLegendValue} section='yAxis' fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />
1017
+ {config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />}
1000
1018
  <TextField value={config.yAxis.numTicks} placeholder='Auto' type='number' section='yAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1001
1019
  <TextField
1002
1020
  value={config.yAxis.size}
@@ -1017,11 +1035,29 @@ const EditorPanel = () => {
1017
1035
  </Tooltip>
1018
1036
  }
1019
1037
  />
1038
+ {config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
1020
1039
  {config.orientation !== 'horizontal' && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Display Gridlines' updateField={updateField} />}
1021
1040
  </>
1022
1041
  )}
1023
1042
  <span className='divider-heading'>Number Formatting</span>
1024
1043
  <CheckBox value={config.dataFormat.commas} section='dataFormat' fieldName='commas' label='Add commas' updateField={updateField} />
1044
+ <CheckBox
1045
+ value={config.dataFormat.abbreviated}
1046
+ section='dataFormat'
1047
+ fieldName='abbreviated'
1048
+ label='Abbreviate Axis Values'
1049
+ updateField={updateField}
1050
+ tooltip={
1051
+ <Tooltip style={{ textTransform: 'none' }}>
1052
+ <Tooltip.Target>
1053
+ <Icon display='question' />
1054
+ </Tooltip.Target>
1055
+ <Tooltip.Content>
1056
+ <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
1057
+ </Tooltip.Content>
1058
+ </Tooltip>
1059
+ }
1060
+ />
1025
1061
  <TextField value={config.dataFormat.roundTo} type='number' section='dataFormat' fieldName='roundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1026
1062
  <div className='two-col-inputs'>
1027
1063
  <TextField
@@ -1390,6 +1426,7 @@ const EditorPanel = () => {
1390
1426
  </Tooltip>
1391
1427
  }
1392
1428
  />
1429
+ <CheckBox value={config.legend.showLegendValuesTooltip} section='legend' fieldName='showLegendValuesTooltip' label='Show Legend Values in Tooltip' updateField={updateField} />
1393
1430
 
1394
1431
  {config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1 && (
1395
1432
  <Select value={config.legend.colorCode} section='legend' fieldName='colorCode' label='Color code by category' initial='Select' updateField={updateField} options={getDataValueOptions(data)} />
@@ -1528,7 +1565,7 @@ const EditorPanel = () => {
1528
1565
 
1529
1566
  {config.series?.some(series => series.type === 'Bar' || series.type === 'Paired Bar') && <Select value={config.barHasBorder} fieldName='barHasBorder' label='Bar Borders' updateField={updateField} options={['true', 'false']} />}
1530
1567
 
1531
- {/* <CheckBox value={config.animate} fieldName="animate" label="Animate Visualization" updateField={updateField} /> */}
1568
+ <CheckBox value={config.animate} fieldName='animate' label='Animate Visualization' updateField={updateField} />
1532
1569
 
1533
1570
  {/*<CheckBox value={config.animateReplay} fieldName="animateReplay" label="Replay Animation When Filters Are Changed" updateField={updateField} />*/}
1534
1571
 
@@ -1536,6 +1573,7 @@ const EditorPanel = () => {
1536
1573
  <Select value={config.lineDatapointStyle} fieldName='lineDatapointStyle' label='Line Datapoint Style' updateField={updateField} options={['hidden', 'hover', 'always show']} />
1537
1574
  )}
1538
1575
 
1576
+ {/* eslint-disable */}
1539
1577
  <label className='header'>
1540
1578
  <span className='edit-label'>Header Theme</span>
1541
1579
  <ul className='color-palette'>
@@ -1555,6 +1593,7 @@ const EditorPanel = () => {
1555
1593
  <label>
1556
1594
  <span className='edit-label'>Chart Color Palette</span>
1557
1595
  </label>
1596
+ {/* eslint-enable */}
1558
1597
  {/* <InputCheckbox fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} /> */}
1559
1598
  <InputToggle fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={isPaletteReversed} />
1560
1599
  <span>Sequential</span>
@@ -1644,9 +1683,9 @@ const EditorPanel = () => {
1644
1683
  />
1645
1684
  </>
1646
1685
  )}
1647
- {config.orientation === 'horizontal' && config.yAxis.labelPlacement !== 'On Bar' && <TextField type='number' value={config.barHeight || '25'} fieldName='barHeight' label='Bar Thickness' updateField={updateField} min='15' />}
1686
+ {config.orientation === 'horizontal' && !config.isLollipopChart && config.yAxis.labelPlacement !== 'On Bar' && <TextField type='number' value={config.barHeight || '25'} fieldName='barHeight' label=' Bar Thickness' updateField={updateField} min='15' />}
1648
1687
  {((config.visualizationType === 'Bar' && config.orientation !== 'horizontal') || config.visualizationType === 'Combo') && <TextField value={config.barThickness} type='number' fieldName='barThickness' label='Bar Thickness' updateField={updateField} />}
1649
-
1688
+ {config.orientation === 'horizontal' && <TextField type='number' value={config.barSpace || '20'} fieldName='barSpace' label='Bar Space' updateField={updateField} min='0' />}
1650
1689
  {(config.visualizationType === 'Bar' || config.visualizationType === 'Line' || config.visualizationType === 'Combo') && <CheckBox value={config.topAxis.hasLine} section='topAxis' fieldName='hasLine' label='Add Top Axis Line' updateField={updateField} />}
1651
1690
 
1652
1691
  {config.visualizationType === 'Spark Line' && (
@@ -1658,6 +1697,11 @@ const EditorPanel = () => {
1658
1697
  <CheckBox value={config.visual?.hideBackgroundColor} section='visual' fieldName='hideBackgroundColor' label='Hide Background Color' updateField={updateField} />
1659
1698
  </div>
1660
1699
  )}
1700
+
1701
+ {(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && <CheckBox value={config.showLineSeriesLabels} fieldName='showLineSeriesLabels' label='Append Series Name to End of Line Charts' updateField={updateField} />}
1702
+ {(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && config.showLineSeriesLabels && (
1703
+ <CheckBox value={config.colorMatchLineSeriesLabels} fieldName='colorMatchLineSeriesLabels' label='Match Series Color to Name at End of Line Charts' updateField={updateField} />
1704
+ )}
1661
1705
  </AccordionItemPanel>
1662
1706
  </AccordionItem>
1663
1707
 
@@ -1706,6 +1750,9 @@ const EditorPanel = () => {
1706
1750
  {config.table.limitHeight && <TextField value={config.table.height} section='table' fieldName='height' label='Data Table Height' type='number' min='0' max='500' placeholder='Height(px)' updateField={updateField} />}
1707
1751
  <CheckBox value={config.table.expanded} section='table' fieldName='expanded' label='Expanded by Default' updateField={updateField} />
1708
1752
  <CheckBox value={config.table.download} section='table' fieldName='download' label='Display Download Button' updateField={updateField} />
1753
+ <CheckBox value={config.table.showDownloadUrl} section='table' fieldName='showDownloadUrl' label='Display Link to Dataset' updateField={updateField} />
1754
+ {/* <CheckBox value={config.table.showDownloadImgButton} section='table' fieldName='showDownloadImgButton' label='Display Image Button' updateField={updateField} /> */}
1755
+ {/* <CheckBox value={config.table.showDownloadPdfButton} section='table' fieldName='showDownloadPdfButton' label='Display PDF Button' updateField={updateField} /> */}
1709
1756
  <TextField value={config.table.label} section='table' fieldName='label' label='Label' updateField={updateField} />
1710
1757
  {config.visualizationType !== 'Pie' && <TextField value={config.table.indexLabel} section='table' fieldName='indexLabel' label='Index Column Header' updateField={updateField} />}
1711
1758
  </AccordionItemPanel>