@cdc/chart 4.23.4 → 4.23.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/cdcchart.js +52384 -50875
  2. package/examples/feature/__data__/planet-example-data.json +2 -19
  3. package/examples/feature/__data__/planet-logaritmic-data.json +56 -0
  4. package/examples/feature/area/area-chart-category.json +240 -0
  5. package/examples/feature/bar/example-bar-chart.json +544 -22
  6. package/examples/feature/bar/planet-chart-logaritmic-config.json +170 -0
  7. package/examples/feature/boxplot/valid-boxplot.csv +17 -0
  8. package/examples/feature/filters/filter-testing.json +37 -3
  9. package/examples/feature/forecasting/random_data.csv +366 -0
  10. package/examples/feature/line/line-chart.json +2 -2
  11. package/examples/feature/test-highlight/test-highlight-2.json +789 -0
  12. package/examples/feature/test-highlight/test-highlight-vertical.json +561 -0
  13. package/examples/feature/test-highlight/test-highlight.json +100 -0
  14. package/examples/feature/tests-non-numerics/stacked-vertical-bar-example-nonnumerics.json +1 -2
  15. package/examples/gallery/bar-chart-horizontal/horizontal-highlight.json +345 -0
  16. package/index.html +8 -8
  17. package/package.json +2 -2
  18. package/src/CdcChart.jsx +294 -14
  19. package/src/components/AreaChart.jsx +27 -20
  20. package/src/components/BarChart.jsx +85 -25
  21. package/src/components/DeviationBar.jsx +32 -32
  22. package/src/components/EditorPanel.jsx +1105 -184
  23. package/src/components/Legend.jsx +39 -3
  24. package/src/components/LineChart.jsx +1 -8
  25. package/src/components/LinearChart.jsx +121 -270
  26. package/src/data/initial-state.js +18 -3
  27. package/src/hooks/useHighlightedBars.js +154 -0
  28. package/src/hooks/useMinMax.js +92 -0
  29. package/src/hooks/useReduceData.js +31 -57
  30. package/src/hooks/useScales.js +202 -0
  31. /package/examples/feature/area/{area-chart.json → area-chart-date.json} +0 -0
@@ -17,8 +17,8 @@ import Tooltip from '@cdc/core/components/ui/Tooltip'
17
17
  import Icon from '@cdc/core/components/ui/Icon'
18
18
  import useReduceData from '../hooks/useReduceData'
19
19
  import useRightAxis from '../hooks/useRightAxis'
20
- import * as allCurves from '@visx/curve'
21
20
  import { useFilters } from '@cdc/core/components/Filters'
21
+ import { useHighlightedBars } from '../hooks/useHighlightedBars'
22
22
 
23
23
  /* eslint-disable react-hooks/rules-of-hooks */
24
24
  const TextField = memo(({ label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = 'input', i = null, min = null, ...attributes }) => {
@@ -207,7 +207,7 @@ const Regions = memo(({ config, updateConfig }) => {
207
207
  const headerColors = ['theme-blue', 'theme-purple', 'theme-brown', 'theme-teal', 'theme-pink', 'theme-orange', 'theme-slate', 'theme-indigo', 'theme-cyan', 'theme-green', 'theme-amber']
208
208
 
209
209
  const EditorPanel = () => {
210
- const { config, updateConfig, transformedData: data, loading, colorPalettes, twoColorPalette, unfilteredData, excludedData, isDashboard, setParentConfig, missingRequiredSections, isDebug, setFilteredData } = useContext(ConfigContext)
210
+ const { config, updateConfig, transformedData: data, loading, colorPalettes, twoColorPalette, unfilteredData, excludedData, isDashboard, setParentConfig, missingRequiredSections, isDebug, setFilteredData, lineOptions } = useContext(ConfigContext)
211
211
 
212
212
  const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
213
213
 
@@ -295,6 +295,8 @@ const EditorPanel = () => {
295
295
  }
296
296
 
297
297
  const updateField = (section, subsection, fieldName, newValue) => {
298
+ if (isDebug) console.log('#COVE: CHART: EditorPanel: section, subsection, fieldName, newValue', section, subsection, fieldName, newValue) // eslint-disable-line
299
+
298
300
  if (section === 'boxplot' && subsection === 'legend') {
299
301
  updateConfig({
300
302
  ...config,
@@ -322,6 +324,20 @@ const EditorPanel = () => {
322
324
  })
323
325
  return
324
326
  }
327
+
328
+ if (section === 'columns' && subsection !== '' && fieldName !== '') {
329
+ updateConfig({
330
+ ...config,
331
+ [section]: {
332
+ ...config[section],
333
+ [subsection]: {
334
+ ...config[section][subsection],
335
+ [fieldName]: newValue
336
+ }
337
+ }
338
+ })
339
+ return
340
+ }
325
341
  if (null === section && null === subsection) {
326
342
  let updatedConfig = { ...config, [fieldName]: newValue }
327
343
  enforceRestrictions(updatedConfig)
@@ -490,7 +506,6 @@ const EditorPanel = () => {
490
506
 
491
507
  const getColumns = (filter = true) => {
492
508
  let columns = {}
493
-
494
509
  unfilteredData.forEach(row => {
495
510
  Object.keys(row).forEach(columnName => (columns[columnName] = true))
496
511
  })
@@ -598,6 +613,24 @@ const EditorPanel = () => {
598
613
  // eslint-disable-next-line react-hooks/exhaustive-deps
599
614
  }, [config])
600
615
 
616
+ // when the orientation changes, swap x and y axis anchors
617
+ useEffect(() => {
618
+ const prevXAnchors = config.xAxis.anchors.length > 0 ? config.xAxis.anchors : []
619
+ const prevYAnchors = config.yAxis.anchors.length > 0 ? config.yAxis.anchors : []
620
+
621
+ updateConfig({
622
+ ...config,
623
+ xAxis: {
624
+ ...config.xAxis,
625
+ anchors: prevYAnchors
626
+ },
627
+ yAxis: {
628
+ ...config.yAxis,
629
+ anchors: prevXAnchors
630
+ }
631
+ })
632
+ }, [config.orientation])
633
+
601
634
  // Set paired bars to be horizontal, even though that option doesn't display
602
635
  useEffect(() => {
603
636
  if (config.visualizationType === 'Paired Bar') {
@@ -697,6 +730,24 @@ const EditorPanel = () => {
697
730
  }
698
731
  }
699
732
 
733
+ const visHasAnchors = () => {
734
+ const { visualizationType } = config
735
+ switch (visualizationType) {
736
+ case 'Area Chart':
737
+ return true
738
+ case 'Combo':
739
+ return true
740
+ case 'Line':
741
+ return true
742
+ case 'Bar':
743
+ return true
744
+ case 'Scatter Plot':
745
+ return true
746
+ default:
747
+ return false
748
+ }
749
+ }
750
+
700
751
  const visHasBarBorders = () => {
701
752
  const { series, visualizationType } = config
702
753
  if (visualizationType === 'Box Plot') return false
@@ -737,9 +788,7 @@ const EditorPanel = () => {
737
788
  default:
738
789
  message = ''
739
790
  }
740
- setWarningMsg(function (prevMsg) {
741
- return { ...prevMsg, maxMsg: message }
742
- })
791
+ setWarningMsg(prevMsg => ({ ...prevMsg, maxMsg: message }))
743
792
  }
744
793
 
745
794
  const validateMinValue = () => {
@@ -748,27 +797,28 @@ const EditorPanel = () => {
748
797
  let message = ''
749
798
 
750
799
  switch (true) {
800
+ case config.useLogScale && ['Line', 'Combo', 'Bar'].includes(config.visualizationType) && enteredValue < 0:
801
+ message = 'Negative numbers are not supported in logarithmic scale'
802
+ break
751
803
  case (config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && enteredValue && parseFloat(enteredValue) > minVal:
752
- message = 'Value must be less than ' + minValue
804
+ message = 'Value should not exceed ' + minValue
753
805
  break
754
806
  case config.visualizationType === 'Combo' && isAllLine && enteredValue && parseFloat(enteredValue) > minVal:
755
- message = 'Value must be less than ' + minValue
807
+ message = 'Value should not exceed ' + minValue
756
808
  break
757
809
  case (config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && enteredValue && minVal > 0 && parseFloat(enteredValue) > 0:
758
- message = 'Value must be less than or equal to 0'
810
+ message = config.useLogScale ? 'Value must be equal to 0' : 'Value must be less than or equal to 0'
759
811
  break
760
812
  case config.visualizationType === 'Deviation Bar' && parseFloat(enteredValue) >= Math.min(minVal, config.xAxis.target):
761
813
  message = 'Value must be less than ' + Math.min(minVal, config.xAxis.target)
762
814
  break
763
815
  case config.visualizationType !== 'Deviation Bar' && enteredValue && minVal < 0 && parseFloat(enteredValue) > minVal:
764
- message = 'Value must be less than ' + minValue
816
+ message = 'Value should not exceed ' + minValue
765
817
  break
766
818
  default:
767
819
  message = ''
768
820
  }
769
- setWarningMsg(function (prevMsg) {
770
- return { ...prevMsg, minMsg: message }
771
- })
821
+ setWarningMsg(prevMsg => ({ ...prevMsg, minMsg: message }))
772
822
  }
773
823
  useEffect(() => {
774
824
  validateMinValue()
@@ -777,7 +827,7 @@ const EditorPanel = () => {
777
827
 
778
828
  // prettier-ignore
779
829
  const enabledChartTypes = [
780
- // 'Area Chart',
830
+ 'Area Chart',
781
831
  'Bar',
782
832
  'Box Plot',
783
833
  'Combo',
@@ -823,6 +873,150 @@ const EditorPanel = () => {
823
873
 
824
874
  const chartsWithOptions = ['Area Chart', 'Combo', 'Line']
825
875
 
876
+ const columnsOptions = [
877
+ <option value='' key={'Select Option'}>
878
+ - Select Option -
879
+ </option>
880
+ ]
881
+
882
+ if (config.data && config.series) {
883
+ Object.keys(config.data[0]).map(colName => {
884
+ // OMIT ANY COLUMNS THAT ARE IN DATA SERIES!
885
+ const found = config?.series.some(el => el.dataKey === colName)
886
+ if (colName !== config.xAxis.dataKey && !found) {
887
+ // if not the index then add it
888
+ return columnsOptions.push(
889
+ <option value={colName} key={colName}>
890
+ {colName}
891
+ </option>
892
+ )
893
+ }
894
+ })
895
+
896
+ let columnsByKey = {}
897
+ config.data.forEach(datum => {
898
+ Object.keys(datum).forEach(key => {
899
+ columnsByKey[key] = columnsByKey[key] || []
900
+ const value = typeof datum[key] === 'number' ? datum[key].toString() : datum[key]
901
+
902
+ if (columnsByKey[key].indexOf(value) === -1) {
903
+ columnsByKey[key].push(value)
904
+ }
905
+ })
906
+ })
907
+ }
908
+
909
+ // for pie charts
910
+ if (!config.data && data) {
911
+ if (!data[0]) return
912
+ Object.keys(data[0]).map(colName => {
913
+ // OMIT ANY COLUMNS THAT ARE IN DATA SERIES!
914
+ const found = data.some(el => el.dataKey === colName)
915
+ if (colName !== config.xAxis.dataKey && !found) {
916
+ // if not the index then add it
917
+ return columnsOptions.push(
918
+ <option value={colName} key={colName}>
919
+ {colName}
920
+ </option>
921
+ )
922
+ }
923
+ })
924
+
925
+ let columnsByKey = {}
926
+ data.forEach(datum => {
927
+ Object.keys(datum).forEach(key => {
928
+ columnsByKey[key] = columnsByKey[key] || []
929
+ const value = typeof datum[key] === 'number' ? datum[key].toString() : datum[key]
930
+
931
+ if (columnsByKey[key].indexOf(value) === -1) {
932
+ columnsByKey[key].push(value)
933
+ }
934
+ })
935
+ })
936
+ }
937
+
938
+ // prevents adding duplicates
939
+ const additionalColumns = Object.keys(config.columns).filter(value => {
940
+ const defaultCols = [config.xAxis.dataKey] // ['geo', 'navigate', 'primary', 'latitude', 'longitude']
941
+
942
+ if (true === defaultCols.includes(value)) {
943
+ return false
944
+ }
945
+ return true
946
+ })
947
+
948
+ // just adds a new column but not set to any data yet
949
+ const addAdditionalColumn = number => {
950
+ const columnKey = `additionalColumn${number}`
951
+
952
+ updateConfig({
953
+ ...config,
954
+ columns: {
955
+ ...config.columns,
956
+ [columnKey]: {
957
+ label: 'New Column',
958
+ dataTable: false,
959
+ tooltips: false,
960
+ prefix: '',
961
+ suffix: ''
962
+ }
963
+ }
964
+ })
965
+ }
966
+
967
+ const removeAdditionalColumn = columnName => {
968
+ const newColumns = config.columns
969
+
970
+ delete newColumns[columnName]
971
+
972
+ updateConfig({
973
+ ...config,
974
+ columns: newColumns
975
+ })
976
+ }
977
+
978
+ const editColumn = async (addCol, columnName, setval) => {
979
+ // not using special classes like in map editorpanel so removed those cases
980
+ switch (columnName) {
981
+ case 'name':
982
+ updateConfig({
983
+ ...config,
984
+ columns: {
985
+ ...config.columns,
986
+ [addCol]: {
987
+ ...config.columns[addCol],
988
+ [columnName]: setval
989
+ }
990
+ }
991
+ })
992
+ break
993
+ default:
994
+ updateConfig({
995
+ ...config,
996
+ columns: {
997
+ ...config.columns,
998
+ [addCol]: {
999
+ ...config.columns[addCol],
1000
+ [columnName]: setval
1001
+ }
1002
+ }
1003
+ })
1004
+ break
1005
+ }
1006
+ }
1007
+
1008
+ // prettier-ignore
1009
+ const {
1010
+ highlightedBarValues,
1011
+ highlightedSeriesValues,
1012
+ handleUpdateHighlightedBar,
1013
+ handleAddNewHighlightedBar,
1014
+ handleRemoveHighlightedBar,
1015
+ handleUpdateHighlightedBarColor,
1016
+ handleHighlightedBarLegendLabel,
1017
+ handleUpdateHighlightedBorderWidth
1018
+ } = useHighlightedBars(config, updateConfig)
1019
+
826
1020
  return (
827
1021
  <ErrorBoundary component='EditorPanel'>
828
1022
  {config.newViz && <Confirm />}
@@ -955,7 +1149,6 @@ const EditorPanel = () => {
955
1149
  {config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
956
1150
  </AccordionItemPanel>
957
1151
  </AccordionItem>
958
-
959
1152
  {config.visualizationType !== 'Pie' && (
960
1153
  <AccordionItem>
961
1154
  <AccordionItemHeading>
@@ -1186,7 +1379,6 @@ const EditorPanel = () => {
1186
1379
  </AccordionItemPanel>
1187
1380
  </AccordionItem>
1188
1381
  )}
1189
-
1190
1382
  {config.visualizationType === 'Box Plot' && (
1191
1383
  <AccordionItem>
1192
1384
  <AccordionItemHeading>
@@ -1363,7 +1555,6 @@ const EditorPanel = () => {
1363
1555
  </AccordionItemPanel>
1364
1556
  </AccordionItem>
1365
1557
  )}
1366
-
1367
1558
  <AccordionItem>
1368
1559
  <AccordionItemHeading>
1369
1560
  <AccordionItemButton>
@@ -1424,6 +1615,7 @@ const EditorPanel = () => {
1424
1615
  {config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
1425
1616
  {config.orientation !== 'horizontal' && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Display Gridlines' updateField={updateField} />}
1426
1617
  <CheckBox value={config.yAxis.enablePadding} section='yAxis' fieldName='enablePadding' label='Add Padding to Value Axis Scale' updateField={updateField} />
1618
+ {config.visualizationSubType === 'regular' && <CheckBox value={config.useLogScale} fieldName='useLogScale' label='use logarithmic scale' updateField={updateField} />}
1427
1619
  </>
1428
1620
  )}
1429
1621
  <span className='divider-heading'>Number Formatting</span>
@@ -1508,6 +1700,7 @@ const EditorPanel = () => {
1508
1700
  <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1509
1701
  <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1510
1702
  <CheckBox value={config.yAxis.hideTicks} section='yAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1703
+
1511
1704
  <TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='max value' placeholder='Auto' updateField={updateField} />
1512
1705
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1513
1706
  <TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />
@@ -1515,9 +1708,260 @@ const EditorPanel = () => {
1515
1708
  </>
1516
1709
  )
1517
1710
  )}
1711
+
1712
+ {/* start: anchors */}
1713
+ {visHasAnchors() && config.orientation !== 'horizontal' ? (
1714
+ <div className='edit-block'>
1715
+ <h3>Anchors</h3>
1716
+ <Accordion allowZeroExpanded>
1717
+ {config.yAxis?.anchors?.map((anchor, index) => (
1718
+ <AccordionItem className='series-item series-item--chart'>
1719
+ <AccordionItemHeading className='series-item__title'>
1720
+ <>
1721
+ <AccordionItemButton className={'accordion__button accordion__button'}>
1722
+ Anchor {index + 1}
1723
+ <button
1724
+ className='series-list__remove'
1725
+ onClick={e => {
1726
+ e.preventDefault()
1727
+ const copiedAnchorGroups = [...config.yAxis.anchors]
1728
+ copiedAnchorGroups.splice(index, 1)
1729
+ updateConfig({
1730
+ ...config,
1731
+ yAxis: {
1732
+ ...config.yAxis,
1733
+ anchors: copiedAnchorGroups
1734
+ }
1735
+ })
1736
+ }}
1737
+ >
1738
+ Remove
1739
+ </button>
1740
+ </AccordionItemButton>
1741
+ </>
1742
+ </AccordionItemHeading>
1743
+ <AccordionItemPanel>
1744
+ <label>
1745
+ <span>Anchor Value</span>
1746
+ <Tooltip style={{ textTransform: 'none' }}>
1747
+ <Tooltip.Target>
1748
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1749
+ </Tooltip.Target>
1750
+ <Tooltip.Content>
1751
+ <p>Enter the value as its shown in the data column</p>
1752
+ </Tooltip.Content>
1753
+ </Tooltip>
1754
+ <input
1755
+ type='text'
1756
+ value={config.yAxis.anchors[index].value ? config.yAxis.anchors[index].value : ''}
1757
+ onChange={e => {
1758
+ e.preventDefault()
1759
+ const copiedAnchors = [...config.yAxis.anchors]
1760
+ copiedAnchors[index].value = e.target.value
1761
+ updateConfig({
1762
+ ...config,
1763
+ yAxis: {
1764
+ ...config.yAxis,
1765
+ anchors: copiedAnchors
1766
+ }
1767
+ })
1768
+ }}
1769
+ />
1770
+ </label>
1771
+
1772
+ <label>
1773
+ <span>Anchor Color</span>
1774
+ <input
1775
+ type='text'
1776
+ value={config.yAxis.anchors[index].color ? config.yAxis.anchors[index].color : ''}
1777
+ onChange={e => {
1778
+ e.preventDefault()
1779
+ const copiedAnchors = [...config.yAxis.anchors]
1780
+ copiedAnchors[index].color = e.target.value
1781
+ updateConfig({
1782
+ ...config,
1783
+ yAxis: {
1784
+ ...config.yAxis,
1785
+ anchors: copiedAnchors
1786
+ }
1787
+ })
1788
+ }}
1789
+ />
1790
+ </label>
1791
+
1792
+ <label>
1793
+ Anchor Line Style
1794
+ <select
1795
+ value={config.yAxis.anchors[index].lineStyle || ''}
1796
+ onChange={e => {
1797
+ const copiedAnchors = [...config.yAxis.anchors]
1798
+ copiedAnchors[index].lineStyle = e.target.value
1799
+ updateConfig({
1800
+ ...config,
1801
+ yAxis: {
1802
+ ...config.yAxis,
1803
+ anchors: copiedAnchors
1804
+ }
1805
+ })
1806
+ }}
1807
+ >
1808
+ <option>Select</option>
1809
+ {lineOptions.map(line => (
1810
+ <option key={line.key}>{line.value}</option>
1811
+ ))}
1812
+ </select>
1813
+ </label>
1814
+ </AccordionItemPanel>
1815
+ </AccordionItem>
1816
+ ))}
1817
+ </Accordion>
1818
+
1819
+ <button
1820
+ className='btn full-width'
1821
+ onClick={e => {
1822
+ e.preventDefault()
1823
+ const anchors = [...config.yAxis.anchors]
1824
+ anchors.push({})
1825
+ updateConfig({
1826
+ ...config,
1827
+ yAxis: {
1828
+ ...config.yAxis,
1829
+ anchors
1830
+ }
1831
+ })
1832
+ }}
1833
+ >
1834
+ Add Anchor
1835
+ </button>
1836
+ </div>
1837
+ ) : (
1838
+ <div className='edit-block'>
1839
+ <h3>Anchors</h3>
1840
+ <Accordion allowZeroExpanded>
1841
+ {config.xAxis?.anchors?.map((anchor, index) => (
1842
+ <AccordionItem className='series-item series-item--chart'>
1843
+ <AccordionItemHeading className='series-item__title'>
1844
+ <>
1845
+ <AccordionItemButton className={'accordion__button accordion__button'}>
1846
+ Anchor {index + 1}
1847
+ <button
1848
+ className='series-list__remove'
1849
+ onClick={e => {
1850
+ e.preventDefault()
1851
+ const copiedAnchorGroups = [...config.xAxis.anchors]
1852
+ copiedAnchorGroups.splice(index, 1)
1853
+ updateConfig({
1854
+ ...config,
1855
+ xAxis: {
1856
+ ...config.xAxis,
1857
+ anchors: copiedAnchorGroups
1858
+ }
1859
+ })
1860
+ }}
1861
+ >
1862
+ Remove
1863
+ </button>
1864
+ </AccordionItemButton>
1865
+ </>
1866
+ </AccordionItemHeading>
1867
+ <AccordionItemPanel>
1868
+ <label>
1869
+ <span>Anchor Value</span>
1870
+ <Tooltip style={{ textTransform: 'none' }}>
1871
+ <Tooltip.Target>
1872
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1873
+ </Tooltip.Target>
1874
+ <Tooltip.Content>
1875
+ <p>Enter the value as its shown in the data column</p>
1876
+ </Tooltip.Content>
1877
+ </Tooltip>
1878
+ <input
1879
+ type='text'
1880
+ value={config.xAxis.anchors[index].value ? config.xAxis.anchors[index].value : ''}
1881
+ onChange={e => {
1882
+ e.preventDefault()
1883
+ const copiedAnchors = [...config.xAxis.anchors]
1884
+ copiedAnchors[index].value = e.target.value
1885
+ updateConfig({
1886
+ ...config,
1887
+ xAxis: {
1888
+ ...config.xAxis,
1889
+ anchors: copiedAnchors
1890
+ }
1891
+ })
1892
+ }}
1893
+ />
1894
+ </label>
1895
+
1896
+ <label>
1897
+ <span>Anchor Color</span>
1898
+ <input
1899
+ type='text'
1900
+ value={config.xAxis.anchors[index].color ? config.xAxis.anchors[index].color : ''}
1901
+ onChange={e => {
1902
+ e.preventDefault()
1903
+ const copiedAnchors = [...config.xAxis.anchors]
1904
+ copiedAnchors[index].color = e.target.value
1905
+ updateConfig({
1906
+ ...config,
1907
+ xAxis: {
1908
+ ...config.xAxis,
1909
+ anchors: copiedAnchors
1910
+ }
1911
+ })
1912
+ }}
1913
+ />
1914
+ </label>
1915
+
1916
+ <label>
1917
+ Anchor Line Style
1918
+ <select
1919
+ value={config.xAxis.anchors[index].lineStyle || ''}
1920
+ onChange={e => {
1921
+ const copiedAnchors = [...config.xAxis.anchors]
1922
+ copiedAnchors[index].lineStyle = e.target.value
1923
+ updateConfig({
1924
+ ...config,
1925
+ xAxis: {
1926
+ ...config.xAxis,
1927
+ anchors: copiedAnchors
1928
+ }
1929
+ })
1930
+ }}
1931
+ >
1932
+ <option>Select</option>
1933
+ {lineOptions.map(line => (
1934
+ <option key={line.key}>{line.value}</option>
1935
+ ))}
1936
+ </select>
1937
+ </label>
1938
+ </AccordionItemPanel>
1939
+ </AccordionItem>
1940
+ ))}
1941
+ </Accordion>
1942
+
1943
+ <button
1944
+ className='btn full-width'
1945
+ onClick={e => {
1946
+ e.preventDefault()
1947
+ const anchors = [...config.xAxis.anchors]
1948
+ anchors.push({})
1949
+ updateConfig({
1950
+ ...config,
1951
+ xAxis: {
1952
+ ...config.xAxis,
1953
+ anchors
1954
+ }
1955
+ })
1956
+ }}
1957
+ >
1958
+ Add Anchor
1959
+ </button>
1960
+ </div>
1961
+ )}
1962
+ {/* end: anchors */}
1518
1963
  </AccordionItemPanel>
1519
1964
  </AccordionItem>
1520
-
1521
1965
  {/* Right Value Axis Settings */}
1522
1966
  {hasRightAxis && (
1523
1967
  <AccordionItem>
@@ -1578,7 +2022,6 @@ const EditorPanel = () => {
1578
2022
  </AccordionItemPanel>
1579
2023
  </AccordionItem>
1580
2024
  )}
1581
-
1582
2025
  <AccordionItem>
1583
2026
  <AccordionItemHeading>
1584
2027
  <AccordionItemButton>
@@ -1795,6 +2238,46 @@ const EditorPanel = () => {
1795
2238
  <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1796
2239
  </>
1797
2240
  )}
2241
+
2242
+ {config.series?.length === 1 && config.visualizationType === 'Bar' && (
2243
+ <>
2244
+ {/* HIGHLIGHTED BARS */}
2245
+ <label htmlFor='barHighlight'>Bar Highlighting</label>
2246
+ {config.series.length === 1 &&
2247
+ highlightedBarValues.map((highlightedBarValue, i) => (
2248
+ <fieldset>
2249
+ <div className='edit-block' key={`highlighted-bar-${i}`}>
2250
+ <button className='remove-column' onClick={e => handleRemoveHighlightedBar(e, i)}>
2251
+ Remove
2252
+ </button>
2253
+ <p>Highlighted Bar {i + 1}</p>
2254
+ <label>
2255
+ <span className='edit-label column-heading'>Value</span>
2256
+ <select value={config.highlightedBarValues[i].value} onChange={e => handleUpdateHighlightedBar(e, i)}>
2257
+ <option value=''>- Select Value -</option>
2258
+ {highlightedSeriesValues && [...new Set(highlightedSeriesValues)].sort().map(option => <option key={`special-class-value-option-${i}-${option}`}>{option}</option>)}
2259
+ </select>
2260
+ </label>
2261
+ <label>
2262
+ <span className='edit-label column-heading'>Color</span>
2263
+ <input type='text' value={config.highlightedBarValues[i].color ? config.highlightedBarValues[i].color : ''} onChange={e => handleUpdateHighlightedBarColor(e, i)} />
2264
+ </label>
2265
+ <label>
2266
+ <span className='edit-label column-heading'>Border Width</span>
2267
+ <input max='5' min='0' type='number' value={config.highlightedBarValues[i].borderWidth ? config.highlightedBarValues[i].borderWidth : ''} onChange={e => handleUpdateHighlightedBorderWidth(e, i)} />
2268
+ </label>
2269
+ <label>
2270
+ <span className='edit-label column-heading'>Legend Label</span>
2271
+ <input type='text' value={config.highlightedBarValues[i].legendLabel ? config.highlightedBarValues[i].legendLabel : ''} onChange={e => handleHighlightedBarLegendLabel(e, i)} />
2272
+ </label>
2273
+ </div>
2274
+ </fieldset>
2275
+ ))}
2276
+ <button className='btn full-width' onClick={e => handleAddNewHighlightedBar(e)}>
2277
+ Add Highlighted Bar
2278
+ </button>
2279
+ </>
2280
+ )}
1798
2281
  </>
1799
2282
  )}
1800
2283
 
@@ -1844,9 +2327,259 @@ const EditorPanel = () => {
1844
2327
  )}
1845
2328
  </>
1846
2329
  )}
2330
+
2331
+ {/* anchors */}
2332
+ {visHasAnchors() && config.orientation !== 'horizontal' ? (
2333
+ <div className='edit-block'>
2334
+ <h3>Anchors</h3>
2335
+ <Accordion allowZeroExpanded>
2336
+ {config.xAxis?.anchors?.map((anchor, index) => (
2337
+ <AccordionItem className='series-item series-item--chart'>
2338
+ <AccordionItemHeading className='series-item__title'>
2339
+ <>
2340
+ <AccordionItemButton className={'accordion__button accordion__button'}>
2341
+ Anchor {index + 1}
2342
+ <button
2343
+ className='series-list__remove'
2344
+ onClick={e => {
2345
+ e.preventDefault()
2346
+ const copiedAnchorGroups = [...config.xAxis.anchors]
2347
+ copiedAnchorGroups.splice(index, 1)
2348
+ updateConfig({
2349
+ ...config,
2350
+ xAxis: {
2351
+ ...config.xAxis,
2352
+ anchors: copiedAnchorGroups
2353
+ }
2354
+ })
2355
+ }}
2356
+ >
2357
+ Remove
2358
+ </button>
2359
+ </AccordionItemButton>
2360
+ </>
2361
+ </AccordionItemHeading>
2362
+ <AccordionItemPanel>
2363
+ <label>
2364
+ <span>Anchor Value</span>
2365
+ <Tooltip style={{ textTransform: 'none' }}>
2366
+ <Tooltip.Target>
2367
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2368
+ </Tooltip.Target>
2369
+ <Tooltip.Content>
2370
+ <p>Enter the value as its shown in the data column</p>
2371
+ </Tooltip.Content>
2372
+ </Tooltip>
2373
+ <input
2374
+ type='text'
2375
+ value={config.xAxis.anchors[index].value ? config.xAxis.anchors[index].value : ''}
2376
+ onChange={e => {
2377
+ e.preventDefault()
2378
+ const copiedAnchors = [...config.xAxis.anchors]
2379
+ copiedAnchors[index].value = e.target.value
2380
+ updateConfig({
2381
+ ...config,
2382
+ xAxis: {
2383
+ ...config.xAxis,
2384
+ anchors: copiedAnchors
2385
+ }
2386
+ })
2387
+ }}
2388
+ />
2389
+ </label>
2390
+
2391
+ <label>
2392
+ <span>Anchor Color</span>
2393
+ <input
2394
+ type='text'
2395
+ value={config.xAxis.anchors[index].color ? config.xAxis.anchors[index].color : ''}
2396
+ onChange={e => {
2397
+ e.preventDefault()
2398
+ const copiedAnchors = [...config.xAxis.anchors]
2399
+ copiedAnchors[index].color = e.target.value
2400
+ updateConfig({
2401
+ ...config,
2402
+ xAxis: {
2403
+ ...config.xAxis,
2404
+ anchors: copiedAnchors
2405
+ }
2406
+ })
2407
+ }}
2408
+ />
2409
+ </label>
2410
+
2411
+ <label>
2412
+ Anchor Line Style
2413
+ <select
2414
+ value={config.xAxis.anchors[index].lineStyle || ''}
2415
+ onChange={e => {
2416
+ const copiedAnchors = [...config.xAxis.anchors]
2417
+ copiedAnchors[index].lineStyle = e.target.value
2418
+ updateConfig({
2419
+ ...config,
2420
+ xAxis: {
2421
+ ...config.xAxis,
2422
+ anchors: copiedAnchors
2423
+ }
2424
+ })
2425
+ }}
2426
+ >
2427
+ <option>Select</option>
2428
+ {lineOptions.map(line => (
2429
+ <option key={line.key}>{line.value}</option>
2430
+ ))}
2431
+ </select>
2432
+ </label>
2433
+ </AccordionItemPanel>
2434
+ </AccordionItem>
2435
+ ))}
2436
+ </Accordion>
2437
+
2438
+ <button
2439
+ className='btn full-width'
2440
+ onClick={e => {
2441
+ e.preventDefault()
2442
+ const anchors = [...config.xAxis.anchors]
2443
+ anchors.push({})
2444
+ updateConfig({
2445
+ ...config,
2446
+ xAxis: {
2447
+ ...config.xAxis,
2448
+ anchors
2449
+ }
2450
+ })
2451
+ }}
2452
+ >
2453
+ Add Anchor
2454
+ </button>
2455
+ </div>
2456
+ ) : (
2457
+ <div className='edit-block'>
2458
+ <h3>Anchors</h3>
2459
+ <Accordion allowZeroExpanded>
2460
+ {config.yAxis?.anchors?.map((anchor, index) => (
2461
+ <AccordionItem className='series-item series-item--chart'>
2462
+ <AccordionItemHeading className='series-item__title'>
2463
+ <>
2464
+ <AccordionItemButton className={'accordion__button accordion__button'}>
2465
+ Anchor {index + 1}
2466
+ <button
2467
+ className='series-list__remove'
2468
+ onClick={e => {
2469
+ e.preventDefault()
2470
+ const copiedAnchorGroups = [...config.yAxis.anchors]
2471
+ copiedAnchorGroups.splice(index, 1)
2472
+ updateConfig({
2473
+ ...config,
2474
+ yAxis: {
2475
+ ...config.yAxis,
2476
+ anchors: copiedAnchorGroups
2477
+ }
2478
+ })
2479
+ }}
2480
+ >
2481
+ Remove
2482
+ </button>
2483
+ </AccordionItemButton>
2484
+ </>
2485
+ </AccordionItemHeading>
2486
+ <AccordionItemPanel>
2487
+ <label>
2488
+ <span>Anchor Value</span>
2489
+ <Tooltip style={{ textTransform: 'none' }}>
2490
+ <Tooltip.Target>
2491
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2492
+ </Tooltip.Target>
2493
+ <Tooltip.Content>
2494
+ <p>Enter the value as its shown in the data column</p>
2495
+ </Tooltip.Content>
2496
+ </Tooltip>
2497
+ <input
2498
+ type='text'
2499
+ value={config.yAxis.anchors[index].value ? config.yAxis.anchors[index].value : ''}
2500
+ onChange={e => {
2501
+ e.preventDefault()
2502
+ const copiedAnchors = [...config.yAxis.anchors]
2503
+ copiedAnchors[index].value = e.target.value
2504
+ updateConfig({
2505
+ ...config,
2506
+ yAxis: {
2507
+ ...config.yAxis,
2508
+ anchors: copiedAnchors
2509
+ }
2510
+ })
2511
+ }}
2512
+ />
2513
+ </label>
2514
+
2515
+ <label>
2516
+ <span>Anchor Color</span>
2517
+ <input
2518
+ type='text'
2519
+ value={config.yAxis.anchors[index].color ? config.yAxis.anchors[index].color : ''}
2520
+ onChange={e => {
2521
+ e.preventDefault()
2522
+ const copiedAnchors = [...config.yAxis.anchors]
2523
+ copiedAnchors[index].color = e.target.value
2524
+ updateConfig({
2525
+ ...config,
2526
+ yAxis: {
2527
+ ...config.yAxis,
2528
+ anchors: copiedAnchors
2529
+ }
2530
+ })
2531
+ }}
2532
+ />
2533
+ </label>
2534
+
2535
+ <label>
2536
+ Anchor Line Style
2537
+ <select
2538
+ value={config.yAxis.anchors[index].lineStyle || ''}
2539
+ onChange={e => {
2540
+ const copiedAnchors = [...config.yAxis.anchors]
2541
+ copiedAnchors[index].lineStyle = e.target.value
2542
+ updateConfig({
2543
+ ...config,
2544
+ yAxis: {
2545
+ ...config.yAxis,
2546
+ anchors: copiedAnchors
2547
+ }
2548
+ })
2549
+ }}
2550
+ >
2551
+ <option>Select</option>
2552
+ {lineOptions.map(line => (
2553
+ <option key={line.key}>{line.value}</option>
2554
+ ))}
2555
+ </select>
2556
+ </label>
2557
+ </AccordionItemPanel>
2558
+ </AccordionItem>
2559
+ ))}
2560
+ </Accordion>
2561
+
2562
+ <button
2563
+ className='btn full-width'
2564
+ onClick={e => {
2565
+ e.preventDefault()
2566
+ const anchors = [...config.yAxis.anchors]
2567
+ anchors.push({})
2568
+ updateConfig({
2569
+ ...config,
2570
+ yAxis: {
2571
+ ...config.yAxis,
2572
+ anchors
2573
+ }
2574
+ })
2575
+ }}
2576
+ >
2577
+ Add Anchor
2578
+ </button>
2579
+ </div>
2580
+ )}
1847
2581
  </AccordionItemPanel>
1848
2582
  </AccordionItem>
1849
-
1850
2583
  {config.visualizationType !== 'Pie' && config.visualizationType !== 'Paired Bar' && (
1851
2584
  <AccordionItem>
1852
2585
  <AccordionItemHeading>
@@ -1856,8 +2589,173 @@ const EditorPanel = () => {
1856
2589
  <Regions config={config} updateConfig={updateConfig} />
1857
2590
  </AccordionItemPanel>
1858
2591
  </AccordionItem>
2592
+ )}{' '}
2593
+ {/* Columns */}
2594
+ {config.visualizationType !== 'Box Plot' && config.table.showVertical && (
2595
+ <AccordionItem>
2596
+ <AccordionItemHeading>
2597
+ <AccordionItemButton>Columns</AccordionItemButton>
2598
+ </AccordionItemHeading>
2599
+ <AccordionItemPanel>
2600
+ {'navigation' !== config.type && (
2601
+ <fieldset className='primary-fieldset edit-block'>
2602
+ <label>
2603
+ <span className='edit-label'>
2604
+ Additional Columns
2605
+ <Tooltip style={{ textTransform: 'none' }}>
2606
+ <Tooltip.Target>
2607
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2608
+ </Tooltip.Target>
2609
+ <Tooltip.Content>
2610
+ <p>You can specify additional columns to display in tooltips and / or the supporting data table.</p>
2611
+ </Tooltip.Content>
2612
+ </Tooltip>
2613
+ </span>
2614
+ </label>
2615
+ {additionalColumns.map(val => (
2616
+ <fieldset className='edit-block' key={val}>
2617
+ <button
2618
+ className='remove-column'
2619
+ onClick={event => {
2620
+ event.preventDefault()
2621
+ removeAdditionalColumn(val)
2622
+ }}
2623
+ >
2624
+ Remove
2625
+ </button>
2626
+ <label>
2627
+ <span className='edit-label column-heading'>Column</span>
2628
+ <select
2629
+ value={config.columns[val] ? config.columns[val].name : columnsOptions[0]}
2630
+ onChange={event => {
2631
+ editColumn(val, 'name', event.target.value)
2632
+ }}
2633
+ >
2634
+ {columnsOptions}
2635
+ </select>
2636
+ </label>
2637
+ <TextField value={config.columns[val].label} section='columns' subsection={val} fieldName='label' label='Label' updateField={updateField} />
2638
+ <ul className='column-edit'>
2639
+ <li className='three-col'>
2640
+ <TextField value={config.columns[val].prefix} section='columns' subsection={val} fieldName='prefix' label='Prefix' updateField={updateField} />
2641
+ <TextField value={config.columns[val].suffix} section='columns' subsection={val} fieldName='suffix' label='Suffix' updateField={updateField} />
2642
+ <TextField type='number' value={config.columns[val].roundToPlace} section='columns' subsection={val} fieldName='roundToPlace' label='Round' updateField={updateField} />
2643
+ </li>
2644
+ <li>
2645
+ <label className='checkbox'>
2646
+ <input
2647
+ type='checkbox'
2648
+ checked={config.columns[val].useCommas}
2649
+ onChange={event => {
2650
+ editColumn(val, 'useCommas', event.target.checked)
2651
+ }}
2652
+ />
2653
+ <span className='edit-label'>Add Commas to Numbers</span>
2654
+ </label>
2655
+ </li>
2656
+ <li>
2657
+ <label className='checkbox'>
2658
+ <input
2659
+ type='checkbox'
2660
+ checked={config.columns[val].dataTable}
2661
+ onChange={event => {
2662
+ editColumn(val, 'dataTable', event.target.checked)
2663
+ }}
2664
+ />
2665
+ <span className='edit-label'>Display in Data Table</span>
2666
+ </label>
2667
+ </li>
2668
+ {/* disable for now */}
2669
+ {/*
2670
+ <li>
2671
+ <label className='checkbox'>
2672
+ <input
2673
+ type='checkbox'
2674
+ checked={config.columns[val].tooltip}
2675
+ onChange={event => {
2676
+ editColumn(val, 'tooltip', event.target.checked)
2677
+ }}
2678
+ />
2679
+ <span className='edit-label'>Display in Tooltips</span>
2680
+ </label>
2681
+ </li>
2682
+ */}
2683
+ </ul>
2684
+ </fieldset>
2685
+ ))}
2686
+ <button
2687
+ className={'btn full-width'}
2688
+ onClick={event => {
2689
+ event.preventDefault()
2690
+ addAdditionalColumn(additionalColumns.length + 1)
2691
+ }}
2692
+ >
2693
+ Add Column
2694
+ </button>
2695
+ </fieldset>
2696
+ )}
2697
+ {'category' === config.legend.type && (
2698
+ <fieldset className='primary-fieldset edit-block'>
2699
+ <label>
2700
+ <span className='edit-label'>
2701
+ Additional Category
2702
+ <Tooltip style={{ textTransform: 'none' }}>
2703
+ <Tooltip.Target>
2704
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2705
+ </Tooltip.Target>
2706
+ <Tooltip.Content>
2707
+ <p>You can provide additional categories to ensure they appear in the legend</p>
2708
+ </Tooltip.Content>
2709
+ </Tooltip>
2710
+ </span>
2711
+ </label>
2712
+ {config.legend.additionalCategories &&
2713
+ config.legend.additionalCategories.map((val, i) => (
2714
+ <fieldset className='edit-block' key={val}>
2715
+ <button
2716
+ className='remove-column'
2717
+ onClick={event => {
2718
+ event.preventDefault()
2719
+ const updatedAdditionaCategories = [...config.legend.additionalCategories]
2720
+ updatedAdditionaCategories.splice(i, 1)
2721
+ updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2722
+ }}
2723
+ >
2724
+ Remove
2725
+ </button>
2726
+ <label>
2727
+ <span className='edit-label column-heading'>Category</span>
2728
+ <TextField
2729
+ value={val}
2730
+ section='legend'
2731
+ subsection={null}
2732
+ fieldName='additionalCategories'
2733
+ updateField={(section, subsection, fieldName, value) => {
2734
+ const updatedAdditionaCategories = [...config.legend.additionalCategories]
2735
+ updatedAdditionaCategories[i] = value
2736
+ updateField(section, subsection, fieldName, updatedAdditionaCategories)
2737
+ }}
2738
+ />
2739
+ </label>
2740
+ </fieldset>
2741
+ ))}
2742
+ <button
2743
+ className={'btn full-width'}
2744
+ onClick={event => {
2745
+ event.preventDefault()
2746
+ const updatedAdditionaCategories = [...(config.legend.additionalCategories || [])]
2747
+ updatedAdditionaCategories.push('')
2748
+ updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2749
+ }}
2750
+ >
2751
+ Add Category
2752
+ </button>
2753
+ </fieldset>
2754
+ )}
2755
+ </AccordionItemPanel>
2756
+ </AccordionItem>
1859
2757
  )}
1860
-
2758
+ {/* End Columns */}
1861
2759
  {visHasLegend() && (
1862
2760
  <AccordionItem>
1863
2761
  <AccordionItemHeading>
@@ -1914,7 +2812,6 @@ const EditorPanel = () => {
1914
2812
  </AccordionItemPanel>
1915
2813
  </AccordionItem>
1916
2814
  )}
1917
-
1918
2815
  <AccordionItem>
1919
2816
  <AccordionItemHeading>
1920
2817
  <AccordionItemButton>Filters</AccordionItemButton>
@@ -1947,99 +2844,102 @@ const EditorPanel = () => {
1947
2844
  <ul className='filters-list'>
1948
2845
  {/* Whether filters should apply onChange or Apply Button */}
1949
2846
 
1950
- {config.filters.map((filter, index) => (
1951
- <fieldset className='edit-block' key={index}>
1952
- <button
1953
- type='button'
1954
- className='remove-column'
1955
- onClick={() => {
1956
- removeFilter(index)
1957
- }}
1958
- >
1959
- Remove
1960
- </button>
1961
- <label>
1962
- <span className='edit-label column-heading'>Filter</span>
1963
- <select
1964
- value={filter.columnName}
1965
- onChange={e => {
1966
- updateFilterProp('columnName', index, e.target.value)
2847
+ {config.filters.map((filter, index) => {
2848
+ if (filter.type === 'url') return <></>
2849
+
2850
+ return (
2851
+ <fieldset className='edit-block' key={index}>
2852
+ <button
2853
+ type='button'
2854
+ className='remove-column'
2855
+ onClick={() => {
2856
+ removeFilter(index)
1967
2857
  }}
1968
2858
  >
1969
- <option value=''>- Select Option -</option>
1970
- {getFilters(true).map((dataKey, index) => (
1971
- <option value={dataKey} key={index}>
1972
- {dataKey}
1973
- </option>
1974
- ))}
1975
- </select>
1976
- </label>
2859
+ Remove
2860
+ </button>
2861
+ <label>
2862
+ <span className='edit-label column-heading'>Filter</span>
2863
+ <select
2864
+ value={filter.columnName}
2865
+ onChange={e => {
2866
+ updateFilterProp('columnName', index, e.target.value)
2867
+ }}
2868
+ >
2869
+ <option value=''>- Select Option -</option>
2870
+ {getFilters(true).map((dataKey, index) => (
2871
+ <option value={dataKey} key={index}>
2872
+ {dataKey}
2873
+ </option>
2874
+ ))}
2875
+ </select>
2876
+ </label>
1977
2877
 
1978
- {/* COMING SOON: 4.23.5 FILTER STYLES */}
1979
- {/* <label>
1980
- <span className='edit-label column-heading'>Filter Style</span>
2878
+ <label>
2879
+ <span className='edit-label column-heading'>Filter Style</span>
1981
2880
 
1982
- <select
1983
- value={filter.filterStyle}
1984
- onChange={e => {
1985
- updateFilterProp('filterStyle', index, e.target.value)
1986
- }}
1987
- >
1988
- {filterStyleOptions.map(item => {
1989
- return <option value={item}>{item}</option>
1990
- })}
1991
- </select>
1992
- </label> */}
1993
- <label>
1994
- <span className='edit-label column-heading'>Label</span>
1995
- <input
1996
- type='text'
1997
- value={filter.label}
1998
- onChange={e => {
1999
- updateFilterProp('label', index, e.target.value)
2000
- }}
2001
- />
2002
- </label>
2881
+ <select
2882
+ value={filter.filterStyle}
2883
+ onChange={e => {
2884
+ updateFilterProp('filterStyle', index, e.target.value)
2885
+ }}
2886
+ >
2887
+ {filterStyleOptions.map(item => {
2888
+ return <option value={item}>{item}</option>
2889
+ })}
2890
+ </select>
2891
+ </label>
2892
+ <label>
2893
+ <span className='edit-label column-heading'>Label</span>
2894
+ <input
2895
+ type='text'
2896
+ value={filter.label}
2897
+ onChange={e => {
2898
+ updateFilterProp('label', index, e.target.value)
2899
+ }}
2900
+ />
2901
+ </label>
2003
2902
 
2004
- <label>
2005
- <span className='edit-filterOrder column-heading'>Filter Order</span>
2006
- <select value={filter.order ? filter.order : 'asc'} onChange={e => updateFilterProp('order', index, e.target.value)}>
2007
- {filterOrderOptions.map((option, index) => {
2008
- return (
2009
- <option value={option.value} key={`filter-${index}`}>
2010
- {option.label}
2011
- </option>
2012
- )
2013
- })}
2014
- </select>
2015
-
2016
- {filter.order === 'cust' && (
2017
- <DragDropContext onDragEnd={({ source, destination }) => handleFilterOrder(source.index, destination.index, index, config.filters[index])}>
2018
- <Droppable droppableId='filter_order'>
2019
- {provided => (
2020
- <ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
2021
- {config.filters[index]?.values.map((value, index) => {
2022
- return (
2023
- <Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
2024
- {(provided, snapshot) => (
2025
- <li>
2026
- <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
2027
- {value}
2028
- </div>
2029
- </li>
2030
- )}
2031
- </Draggable>
2032
- )
2033
- })}
2034
- {provided.placeholder}
2035
- </ul>
2036
- )}
2037
- </Droppable>
2038
- </DragDropContext>
2039
- )}
2040
- </label>
2041
- </fieldset>
2042
- ))}
2903
+ <label>
2904
+ <span className='edit-filterOrder column-heading'>Filter Order</span>
2905
+ <select value={filter.order ? filter.order : 'asc'} onChange={e => updateFilterProp('order', index, e.target.value)}>
2906
+ {filterOrderOptions.map((option, index) => {
2907
+ return (
2908
+ <option value={option.value} key={`filter-${index}`}>
2909
+ {option.label}
2910
+ </option>
2911
+ )
2912
+ })}
2913
+ </select>
2914
+
2915
+ {filter.order === 'cust' && (
2916
+ <DragDropContext onDragEnd={({ source, destination }) => handleFilterOrder(source.index, destination.index, index, config.filters[index])}>
2917
+ <Droppable droppableId='filter_order'>
2918
+ {provided => (
2919
+ <ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
2920
+ {config.filters[index]?.values.map((value, index) => {
2921
+ return (
2922
+ <Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
2923
+ {(provided, snapshot) => (
2924
+ <li>
2925
+ <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
2926
+ {value}
2927
+ </div>
2928
+ </li>
2929
+ )}
2930
+ </Draggable>
2931
+ )
2932
+ })}
2933
+ {provided.placeholder}
2934
+ </ul>
2935
+ )}
2936
+ </Droppable>
2937
+ </DragDropContext>
2938
+ )}
2939
+ </label>
2940
+ </fieldset>
2941
+ )
2942
+ })}
2043
2943
  </ul>
2044
2944
  )}
2045
2945
  {!config.filters && <p style={{ textAlign: 'center' }}>There are currently no filters.</p>}
@@ -2048,7 +2948,6 @@ const EditorPanel = () => {
2048
2948
  </button>
2049
2949
  </AccordionItemPanel>
2050
2950
  </AccordionItem>
2051
-
2052
2951
  <AccordionItem>
2053
2952
  <AccordionItemHeading>
2054
2953
  <AccordionItemButton>Visual</AccordionItemButton>
@@ -2262,79 +3161,101 @@ const EditorPanel = () => {
2262
3161
  )}
2263
3162
  </AccordionItemPanel>
2264
3163
  </AccordionItem>
2265
-
2266
- <AccordionItem>
2267
- <AccordionItemHeading>
2268
- <AccordionItemButton>Data Table</AccordionItemButton>
2269
- </AccordionItemHeading>
2270
- <AccordionItemPanel>
2271
- <TextField
2272
- value={config.table.label}
2273
- updateField={updateField}
2274
- section='table'
2275
- fieldName='label'
2276
- id='tableLabel'
2277
- label='Data Table Title'
2278
- placeholder='Data Table'
2279
- tooltip={
2280
- <Tooltip style={{ textTransform: 'none' }}>
2281
- <Tooltip.Target>
2282
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2283
- </Tooltip.Target>
2284
- <Tooltip.Content>
2285
- <p>Label is required for Data Table for 508 Compliance</p>
2286
- </Tooltip.Content>
2287
- </Tooltip>
2288
- }
2289
- />
2290
- <CheckBox
2291
- value={config.table.show}
2292
- section='table'
2293
- fieldName='show'
2294
- label='Show Data Table'
2295
- updateField={updateField}
2296
- className='column-heading'
2297
- tooltip={
2298
- <Tooltip style={{ textTransform: 'none' }}>
2299
- <Tooltip.Target>
2300
- <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2301
- </Tooltip.Target>
2302
- <Tooltip.Content>
2303
- <p>Hiding the data table may affect accessibility. An alternate form of accessing visualization data is a 508 requirement.</p>
2304
- </Tooltip.Content>
2305
- </Tooltip>
2306
- }
2307
- />
2308
- <TextField
2309
- value={config.table.caption}
2310
- updateField={updateField}
2311
- section='table'
2312
- type='textarea'
2313
- fieldName='caption'
2314
- label='Data Table Caption'
2315
- placeholder=' Data table'
2316
- tooltip={
2317
- <Tooltip style={{ textTransform: 'none' }}>
2318
- <Tooltip.Target>
2319
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2320
- </Tooltip.Target>
2321
- <Tooltip.Content>
2322
- <p>Enter a description of the data table to be read by screen readers.</p>
2323
- </Tooltip.Content>
2324
- </Tooltip>
2325
- }
2326
- />
2327
- <CheckBox value={config.table.limitHeight} section='table' fieldName='limitHeight' label='Limit Table Height' updateField={updateField} />
2328
- {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} />}
2329
- <CheckBox value={config.table.expanded} section='table' fieldName='expanded' label='Expanded by Default' updateField={updateField} />
2330
- {isDashboard && <CheckBox value={config.table.showDataTableLink} section='table' fieldName='showDataTableLink' label='Show Data Table Name & Link' updateField={updateField} />}
2331
- {isLoadedFromUrl && <CheckBox value={config.table.showDownloadUrl} section='table' fieldName='showDownloadUrl' label='Show URL to Automatically Updated Data' updateField={updateField} />}
2332
- <CheckBox value={config.table.download} section='table' fieldName='download' label='Show Download CSV Link' updateField={updateField} />
2333
- {/* <CheckBox value={config.table.showDownloadImgButton} section='table' fieldName='showDownloadImgButton' label='Display Image Button' updateField={updateField} /> */}
2334
- {/* <CheckBox value={config.table.showDownloadPdfButton} section='table' fieldName='showDownloadPdfButton' label='Display PDF Button' updateField={updateField} /> */}
2335
- {config.visualizationType !== 'Pie' && <TextField value={config.table.indexLabel} section='table' fieldName='indexLabel' label='Index Column Header' updateField={updateField} />}
2336
- </AccordionItemPanel>
2337
- </AccordionItem>
3164
+ {/* Spark Line has no data table */}
3165
+ {config.visualizationType !== 'Spark Line' && (
3166
+ <AccordionItem>
3167
+ <AccordionItemHeading>
3168
+ <AccordionItemButton>Data Table</AccordionItemButton>
3169
+ </AccordionItemHeading>
3170
+ <AccordionItemPanel>
3171
+ <TextField
3172
+ value={config.table.label}
3173
+ updateField={updateField}
3174
+ section='table'
3175
+ fieldName='label'
3176
+ id='tableLabel'
3177
+ label='Data Table Title'
3178
+ placeholder='Data Table'
3179
+ tooltip={
3180
+ <Tooltip style={{ textTransform: 'none' }}>
3181
+ <Tooltip.Target>
3182
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3183
+ </Tooltip.Target>
3184
+ <Tooltip.Content>
3185
+ <p>Label is required for Data Table for 508 Compliance</p>
3186
+ </Tooltip.Content>
3187
+ </Tooltip>
3188
+ }
3189
+ />
3190
+ <CheckBox
3191
+ value={config.table.show}
3192
+ section='table'
3193
+ fieldName='show'
3194
+ label='Show Data Table'
3195
+ updateField={updateField}
3196
+ className='column-heading'
3197
+ tooltip={
3198
+ <Tooltip style={{ textTransform: 'none' }}>
3199
+ <Tooltip.Target>
3200
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
3201
+ </Tooltip.Target>
3202
+ <Tooltip.Content>
3203
+ <p>Hiding the data table may affect accessibility. An alternate form of accessing visualization data is a 508 requirement.</p>
3204
+ </Tooltip.Content>
3205
+ </Tooltip>
3206
+ }
3207
+ />
3208
+ {config.visualizationType !== 'Box Plot' && (
3209
+ <CheckBox
3210
+ value={config.table.showVertical}
3211
+ section='table'
3212
+ fieldName='showVertical'
3213
+ label='Show Vertical Data'
3214
+ updateField={updateField}
3215
+ className='column-heading'
3216
+ tooltip={
3217
+ <Tooltip style={{ textTransform: 'none' }}>
3218
+ <Tooltip.Target>
3219
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
3220
+ </Tooltip.Target>
3221
+ <Tooltip.Content>
3222
+ <p>This will draw the data table with vertical data instead of horizontal.</p>
3223
+ </Tooltip.Content>
3224
+ </Tooltip>
3225
+ }
3226
+ />
3227
+ )}
3228
+ <TextField value={config.table.indexLabel} section='table' fieldName='indexLabel' label='Index Column Header' updateField={updateField} />
3229
+ <TextField
3230
+ value={config.table.caption}
3231
+ updateField={updateField}
3232
+ section='table'
3233
+ type='textarea'
3234
+ fieldName='caption'
3235
+ label='Data Table Caption'
3236
+ placeholder=' Data table'
3237
+ tooltip={
3238
+ <Tooltip style={{ textTransform: 'none' }}>
3239
+ <Tooltip.Target>
3240
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
3241
+ </Tooltip.Target>
3242
+ <Tooltip.Content>
3243
+ <p>Enter a description of the data table to be read by screen readers.</p>
3244
+ </Tooltip.Content>
3245
+ </Tooltip>
3246
+ }
3247
+ />
3248
+ <CheckBox value={config.table.limitHeight} section='table' fieldName='limitHeight' label='Limit Table Height' updateField={updateField} />
3249
+ {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} />}
3250
+ <CheckBox value={config.table.expanded} section='table' fieldName='expanded' label='Expanded by Default' updateField={updateField} />
3251
+ {isDashboard && <CheckBox value={config.table.showDataTableLink} section='table' fieldName='showDataTableLink' label='Show Data Table Name & Link' updateField={updateField} />}
3252
+ {isLoadedFromUrl && <CheckBox value={config.table.showDownloadUrl} section='table' fieldName='showDownloadUrl' label='Show URL to Automatically Updated Data' updateField={updateField} />}
3253
+ <CheckBox value={config.table.download} section='table' fieldName='download' label='Show Download CSV Link' updateField={updateField} />
3254
+ {/* <CheckBox value={config.table.showDownloadImgButton} section='table' fieldName='showDownloadImgButton' label='Display Image Button' updateField={updateField} /> */}
3255
+ {/* <CheckBox value={config.table.showDownloadPdfButton} section='table' fieldName='showDownloadPdfButton' label='Display PDF Button' updateField={updateField} /> */}
3256
+ </AccordionItemPanel>
3257
+ </AccordionItem>
3258
+ )}
2338
3259
  </Accordion>
2339
3260
  </form>
2340
3261
  {config.type !== 'Spark Line' && <AdvancedEditor loadConfig={updateConfig} state={config} convertStateToConfig={convertStateToConfig} />}