@cdc/chart 4.23.7 → 4.23.8

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/LICENSE +201 -0
  2. package/dist/cdcchart.js +27964 -26942
  3. package/examples/feature/__data__/area-chart-date-apple.json +5122 -0
  4. package/examples/feature/__data__/city-temperature.json +2198 -0
  5. package/examples/feature/area/area-chart-category.json +45 -45
  6. package/examples/feature/area/area-chart-date-apple.json +10376 -0
  7. package/examples/feature/area/area-chart-date-city-temperature.json +4528 -0
  8. package/examples/feature/area/area-chart-date.json +111 -3
  9. package/examples/feature/forest-plot/broken.json +700 -0
  10. package/examples/feature/forest-plot/data.csv +24 -0
  11. package/examples/feature/forest-plot/forest-plot.json +717 -0
  12. package/examples/feature/pie/planet-pie-example-config.json +1 -1
  13. package/examples/private/confidence_interval_test.json +248 -0
  14. package/examples/private/tooltip-issue.json +45275 -0
  15. package/index.html +13 -11
  16. package/package.json +4 -3
  17. package/src/CdcChart.jsx +24 -14
  18. package/src/components/AreaChart.jsx +84 -59
  19. package/src/components/BarChart.Horizontal.jsx +251 -0
  20. package/src/components/BarChart.StackedHorizontal.jsx +118 -0
  21. package/src/components/BarChart.StackedVertical.jsx +93 -0
  22. package/src/components/BarChart.Vertical.jsx +204 -0
  23. package/src/components/BarChart.jsx +14 -674
  24. package/src/components/BarChartType.jsx +15 -0
  25. package/src/components/BrushHandle.jsx +17 -0
  26. package/src/components/DataTable.jsx +63 -21
  27. package/src/components/EditorPanel.jsx +351 -303
  28. package/src/components/ForestPlot.jsx +191 -0
  29. package/src/components/ForestPlotSettings.jsx +508 -0
  30. package/src/components/LineChart.jsx +2 -2
  31. package/src/components/LinearChart.jsx +115 -310
  32. package/src/data/initial-state.js +43 -0
  33. package/src/hooks/useBarChart.js +186 -0
  34. package/src/hooks/useEditorPermissions.js +218 -0
  35. package/src/hooks/useMinMax.js +15 -3
  36. package/src/hooks/useScales.js +45 -2
  37. package/src/hooks/useTooltip.jsx +407 -0
  38. package/src/scss/main.scss +7 -0
@@ -21,6 +21,9 @@ import { useFilters } from '@cdc/core/components/Filters'
21
21
  import Series from './Series'
22
22
  import { useHighlightedBars } from '../hooks/useHighlightedBars'
23
23
 
24
+ import ForestPlotSettings from './ForestPlotSettings'
25
+ import { useEditorPermissions } from '../hooks/useEditorPermissions'
26
+
24
27
  /* eslint-disable react-hooks/rules-of-hooks */
25
28
  const TextField = memo(({ label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = 'input', i = null, min = null, ...attributes }) => {
26
29
  const [value, setValue] = useState(stateValue)
@@ -138,6 +141,7 @@ const Regions = memo(({ config, updateConfig }) => {
138
141
  updateConfig({ ...config, regions })
139
142
  }
140
143
 
144
+ // only for Regions
141
145
  let updateField = (section, subsection, fieldName, value, i) => regionUpdate(fieldName, value, i)
142
146
 
143
147
  let removeColumn = i => {
@@ -214,6 +218,35 @@ const EditorPanel = () => {
214
218
 
215
219
  const { twoColorPalettes, sequential, nonSequential } = useColorPalette(config, updateConfig)
216
220
 
221
+ const {
222
+ enabledChartTypes,
223
+ visSupportsTooltipLines,
224
+ visSupportsNonSequentialPallete,
225
+ visSupportsSequentialPallete,
226
+ visSupportsReverseColorPalette,
227
+ visHasLabelOnData,
228
+ visHasNumbersOnBars,
229
+ visHasAnchors,
230
+ visHasBarBorders,
231
+ visHasDataCutoff,
232
+ visCanAnimate,
233
+ visHasLegend,
234
+ visSupportsDateCategoryAxisLabel,
235
+ visSupportsDateCategoryAxisLine,
236
+ visSupportsDateCategoryAxisTicks,
237
+ visSupportsDateCategoryTickRotation,
238
+ visSupportsDateCategoryNumTicks,
239
+ visSupportsRegions,
240
+ visSupportsFilters,
241
+ visSupportsValueAxisGridLines,
242
+ visSupportsValueAxisLine,
243
+ visSupportsValueAxisTicks,
244
+ visSupportsValueAxisLabels,
245
+ visSupportsBarSpace,
246
+ visSupportsBarThickness,
247
+ visSupportsDataCutoff
248
+ } = useEditorPermissions()
249
+
217
250
  // argument acts as props
218
251
  const { handleFilterOrder, filterOrderOptions, filterStyleOptions } = useFilters({ config, setConfig: updateConfig, filteredData: data, setFilteredData })
219
252
 
@@ -237,6 +270,11 @@ const EditorPanel = () => {
237
270
  ...config,
238
271
  series: newSeries
239
272
  })
273
+
274
+ // disable brush if categorical - or - for now if not Area Chart
275
+ if (config.xAxis.type === 'categorical' || config.visualizationType !== 'Area Chart') {
276
+ config.showChartBrush = false
277
+ }
240
278
  }, [config.visualizationType]) // eslint-disable-line
241
279
 
242
280
  // Scatter Plots default date/category axis is 'continuous'
@@ -635,6 +673,16 @@ const EditorPanel = () => {
635
673
  })
636
674
  }, [config.orientation])
637
675
 
676
+ // Set paired bars to be horizontal, even though that option doesn't display
677
+ useEffect(() => {
678
+ if (config.visualizationType === 'Paired Bar') {
679
+ updateConfig({
680
+ ...config,
681
+ orientation: 'horizontal'
682
+ })
683
+ }
684
+ }, []) // eslint-disable-line
685
+
638
686
  useEffect(() => {
639
687
  if (config.orientation === 'horizontal') {
640
688
  updateConfig({
@@ -644,6 +692,13 @@ const EditorPanel = () => {
644
692
  }
645
693
  }, [config.isLollipopChart, config.lollipopShape]) // eslint-disable-line
646
694
 
695
+ /// temporary force orientation untill we support Vartical deviaton bar
696
+ useEffect(() => {
697
+ if (config.visualizationType === 'Deviation Bar') {
698
+ updateConfig({ ...config, orientation: 'horizontal' })
699
+ }
700
+ }, [config.visualizationType])
701
+
647
702
  const ExclusionsList = useCallback(() => {
648
703
  const exclusions = [...config.exclusions.keys]
649
704
  return (
@@ -664,91 +719,6 @@ const EditorPanel = () => {
664
719
  )
665
720
  }, [config]) // eslint-disable-line
666
721
 
667
- const visSupportsTooltipLines = () => {
668
- const chartsWithTooltipGuides = ['Combo', 'Forecasting', 'Area Chart', 'Line', 'Bar']
669
- if (chartsWithTooltipGuides.includes(config.visualizationType)) return true
670
- return false
671
- }
672
-
673
- const visHasLegend = () => {
674
- const { visualizationType } = config
675
-
676
- switch (visualizationType) {
677
- case 'Box Plot':
678
- return false
679
- default:
680
- return true
681
- }
682
- }
683
-
684
- const visCanAnimate = () => {
685
- const { visualizationType } = config
686
- switch (visualizationType) {
687
- case 'Area Chart':
688
- return false
689
- case 'Scatter Plot':
690
- return false
691
- case 'Box Plot':
692
- return false
693
- default:
694
- return true
695
- }
696
- }
697
-
698
- const visHasDataCutoff = () => {
699
- const { visualizationType } = config
700
- switch (visualizationType) {
701
- case 'Box Plot':
702
- return false
703
- case 'Pie':
704
- return false
705
- default:
706
- return true
707
- }
708
- }
709
-
710
- const visHasLabelOnData = () => {
711
- const { visualizationType } = config
712
- switch (visualizationType) {
713
- case 'Area Chart':
714
- return false
715
- case 'Box Plot':
716
- return false
717
- case 'Pie':
718
- return false
719
- case 'Scatter Plot':
720
- return false
721
- default:
722
- return true
723
- }
724
- }
725
-
726
- const visHasAnchors = () => {
727
- const { visualizationType } = config
728
- switch (visualizationType) {
729
- case 'Area Chart':
730
- return true
731
- case 'Combo':
732
- return true
733
- case 'Line':
734
- return true
735
- case 'Bar':
736
- return true
737
- case 'Scatter Plot':
738
- return true
739
- default:
740
- return false
741
- }
742
- }
743
-
744
- const visHasBarBorders = () => {
745
- const { series, visualizationType } = config
746
- if (visualizationType === 'Box Plot') return false
747
- if (visualizationType === 'Scatter Plot') return false
748
- if (visualizationType === 'Pie') return false
749
- return series?.some(series => series.type === 'Bar' || series.type === 'Paired Bar' || series.type === 'Deviation Bar')
750
- }
751
-
752
722
  const handleSeriesChange = (idx1, idx2) => {
753
723
  let seriesOrder = config.series
754
724
  let [movedItem] = seriesOrder.splice(idx1, 1)
@@ -759,6 +729,9 @@ const EditorPanel = () => {
759
729
  if (config.isLollipopChart && config?.series?.length > 1) {
760
730
  config.runtime.editorErrorMessage = 'Lollipop charts must use only one data series'
761
731
  }
732
+ if (config.visualizationType === 'Paired Bar' && config?.series?.length !== 2) {
733
+ config.runtime.editorErrorMessage = 'Paired Bar charts must use exactly two data series'
734
+ }
762
735
 
763
736
  if (config.isLollipopChart && config?.series?.length === 0) {
764
737
  config.runtime.editorErrorMessage = 'Add a data series'
@@ -818,21 +791,6 @@ const EditorPanel = () => {
818
791
  validateMaxValue()
819
792
  }, [minValue, maxValue, config]) // eslint-disable-line
820
793
 
821
- // prettier-ignore
822
- const enabledChartTypes = [
823
- 'Area Chart',
824
- 'Bar',
825
- 'Box Plot',
826
- 'Combo',
827
- 'Deviation Bar',
828
- 'Forecasting',
829
- 'Line',
830
- 'Paired Bar',
831
- 'Pie',
832
- 'Scatter Plot',
833
- 'Spark Line'
834
- ]
835
-
836
794
  const isLoadedFromUrl = config?.dataKey?.includes('http://') || config?.dataKey?.includes('https://')
837
795
 
838
796
  // if isDebug = true, then try to set the category and data col to reduce clicking
@@ -877,7 +835,7 @@ const EditorPanel = () => {
877
835
  if (config.data && config.series) {
878
836
  Object.keys(config.data[0]).map(colName => {
879
837
  // OMIT ANY COLUMNS THAT ARE IN DATA SERIES!
880
- const found = config?.series.some(el => el.dataKey === colName)
838
+ const found = config?.series.some(series => series.dataKey === colName)
881
839
  if (colName !== config.xAxis.dataKey && !found) {
882
840
  // if not the index then add it
883
841
  return columnsOptions.push(
@@ -953,7 +911,10 @@ const EditorPanel = () => {
953
911
  dataTable: false,
954
912
  tooltips: false,
955
913
  prefix: '',
956
- suffix: ''
914
+ suffix: '',
915
+ forestPlot: false,
916
+ startingPoint: '0',
917
+ forestPlotAlignRight: false
957
918
  }
958
919
  }
959
920
  })
@@ -1012,6 +973,21 @@ const EditorPanel = () => {
1012
973
  handleUpdateHighlightedBorderWidth
1013
974
  } = useHighlightedBars(config, updateConfig)
1014
975
 
976
+ const updateSeriesTooltip = (column, event) => {
977
+ console.log('tooltip value', event)
978
+
979
+ let updatedColumns = config.columns
980
+
981
+ updatedColumns[column].tooltips = event
982
+
983
+ console.log('updatedColumns', updatedColumns)
984
+
985
+ updateConfig({
986
+ ...config,
987
+ columns: updatedColumns
988
+ })
989
+ }
990
+
1015
991
  return (
1016
992
  <ErrorBoundary component='EditorPanel'>
1017
993
  {config.newViz && <Confirm />}
@@ -1040,7 +1016,7 @@ const EditorPanel = () => {
1040
1016
  <Select value={config.roundingStyle || 'standard'} fieldName='roundingStyle' label='rounding style' updateField={updateField} options={['standard', 'shallow', 'finger']} />
1041
1017
  )}
1042
1018
  {config.visualizationType === 'Bar' && config.orientation === 'horizontal' && <Select value={config.yAxis.labelPlacement || 'Below Bar'} section='yAxis' fieldName='labelPlacement' label='Label Placement' updateField={updateField} options={['Below Bar', 'On Date/Category Axis']} />}
1043
- {config.orientation === 'horizontal' && (config.yAxis.labelPlacement === 'Below Bar' || config.yAxis.labelPlacement === 'On Date/Category Axis' || config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') ? (
1019
+ {visHasNumbersOnBars() ? (
1044
1020
  <CheckBox value={config.yAxis.displayNumbersOnBar} section='yAxis' fieldName='displayNumbersOnBar' label={config.isLollipopChart ? 'Display Numbers after Bar' : 'Display Numbers on Bar'} updateField={updateField} />
1045
1021
  ) : (
1046
1022
  visHasLabelOnData() && <CheckBox value={config.labels} fieldName='labels' label='Display label on data' updateField={updateField} />
@@ -1143,7 +1119,8 @@ const EditorPanel = () => {
1143
1119
  {config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
1144
1120
  </AccordionItemPanel>
1145
1121
  </AccordionItem>
1146
- {config.visualizationType !== 'Pie' && (
1122
+ {config.visualizationType === 'Forest Plot' && <ForestPlotSettings />}
1123
+ {config.visualizationType !== 'Pie' && config.visualizationType !== 'Forest Plot' && (
1147
1124
  <AccordionItem>
1148
1125
  <AccordionItemHeading>
1149
1126
  <AccordionItemButton>Data Series {(!config.series || config.series.length === 0 || (config.visualizationType === 'Paired Bar' && config.series.length < 2)) && <WarningImage width='25' className='warning-icon' />}</AccordionItemButton>
@@ -1345,7 +1322,7 @@ const EditorPanel = () => {
1345
1322
  <AccordionItem>
1346
1323
  <AccordionItemHeading>
1347
1324
  <AccordionItemButton>
1348
- {config.visualizationType !== 'Pie' ? (config.orientation !== 'horizontal' ? 'Left Value Axis' : 'Value Axis') : 'Data Format'}
1325
+ {config.visualizationType === 'Pie' ? 'Data Format' : config.orientation === 'vertical' ? 'Left Value Axis' : 'Value Axis'}
1349
1326
  {config.visualizationType === 'Pie' && !config.yAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1350
1327
  </AccordionItemButton>
1351
1328
  </AccordionItemHeading>
@@ -1425,7 +1402,7 @@ const EditorPanel = () => {
1425
1402
  {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
1426
1403
  {/* <TextField value={config.yAxis.axisPadding} type='number' max={10} min={0} section='yAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
1427
1404
  {config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
1428
- {config.orientation !== 'horizontal' && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Show Gridlines' updateField={updateField} />}
1405
+ {visSupportsValueAxisGridLines() && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Show Gridlines' updateField={updateField} />}
1429
1406
  <CheckBox value={config.yAxis.enablePadding} section='yAxis' fieldName='enablePadding' label='Add Padding to Value Axis Scale' updateField={updateField} />
1430
1407
  {config.visualizationSubType === 'regular' && <CheckBox value={config.useLogScale} fieldName='useLogScale' label='use logarithmic scale' updateField={updateField} />}
1431
1408
  </>
@@ -1491,9 +1468,9 @@ const EditorPanel = () => {
1491
1468
 
1492
1469
  {config.orientation === 'horizontal' ? ( // horizontal - x is vertical y is horizontal
1493
1470
  <>
1494
- <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1495
- <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1496
- <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1471
+ {visSupportsValueAxisLine() && <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
1472
+ {visSupportsValueAxisLabels() && <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
1473
+ {visSupportsValueAxisTicks() && <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />}
1497
1474
  <TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='max value' type='number' placeholder='Auto' updateField={updateField} />
1498
1475
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1499
1476
  <TextField value={config.xAxis.min} section='xAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />
@@ -1839,14 +1816,16 @@ const EditorPanel = () => {
1839
1816
  <AccordionItem>
1840
1817
  <AccordionItemHeading>
1841
1818
  <AccordionItemButton>
1842
- {config.visualizationType !== 'Pie' ? (config.visualizationType === 'Bar' ? 'Date/Category Axis' : 'Date/Category Axis') : 'Segments'}
1819
+ {config.visualizationType === 'Pie' ? 'Segments' : 'Date/Category Axis'}
1843
1820
  {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1844
1821
  </AccordionItemButton>
1845
1822
  </AccordionItemHeading>
1846
1823
  <AccordionItemPanel>
1847
1824
  {config.visualizationType !== 'Pie' && (
1848
1825
  <>
1849
- <Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={config.visualizationType !== 'Scatter Plot' ? ['categorical', 'date'] : ['categorical', 'continuous', 'date']} />
1826
+ {config.visualizationType !== 'Forest Plot' && (
1827
+ <Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={config.visualizationType !== 'Scatter Plot' ? ['categorical', 'date'] : ['categorical', 'continuous', 'date']} />
1828
+ )}
1850
1829
  <Select
1851
1830
  value={config.xAxis.dataKey || setCategoryAxis() || ''}
1852
1831
  section='xAxis'
@@ -2025,7 +2004,8 @@ const EditorPanel = () => {
2025
2004
  )}
2026
2005
  </>
2027
2006
  )}
2028
- <TextField value={config.xAxis.numTicks} placeholder='Auto' type='number' min='1' section='xAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
2007
+
2008
+ {visSupportsDateCategoryNumTicks() && <TextField value={config.xAxis.numTicks} placeholder='Auto' type='number' min='1' section='xAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />}
2029
2009
 
2030
2010
  <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} />
2031
2011
 
@@ -2039,7 +2019,9 @@ const EditorPanel = () => {
2039
2019
  </>
2040
2020
  )}
2041
2021
  {config.orientation === 'vertical' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
2042
- {(config.orientation === 'horizontal' || !config.isResponsiveTicks) && <TextField value={config.xAxis.tickRotation} type='number' min='0' section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
2022
+ {(config.orientation === 'horizontal' || !config.isResponsiveTicks) && visSupportsDateCategoryTickRotation() && (
2023
+ <TextField value={config.xAxis.tickRotation} type='number' min='0' section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />
2024
+ )}
2043
2025
  {config.orientation === 'vertical' && config.isResponsiveTicks && config.visualizationType !== 'Paired Bar' && (
2044
2026
  <TextField
2045
2027
  value={config.xAxis.maxTickRotation}
@@ -2065,8 +2047,8 @@ const EditorPanel = () => {
2065
2047
 
2066
2048
  {config.orientation === 'horizontal' ? (
2067
2049
  <>
2068
- <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
2069
- <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
2050
+ {visSupportsDateCategoryAxisLine() && <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />}
2051
+ {visSupportsDateCategoryAxisLabel() && <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />}
2070
2052
  </>
2071
2053
  ) : (
2072
2054
  <>
@@ -2419,7 +2401,7 @@ const EditorPanel = () => {
2419
2401
  )}
2420
2402
  </AccordionItemPanel>
2421
2403
  </AccordionItem>
2422
- {config.visualizationType !== 'Pie' && config.visualizationType !== 'Paired Bar' && (
2404
+ {visSupportsRegions() && (
2423
2405
  <AccordionItem>
2424
2406
  <AccordionItemHeading>
2425
2407
  <AccordionItemButton>Regions</AccordionItemButton>
@@ -2519,6 +2501,62 @@ const EditorPanel = () => {
2519
2501
  </label>
2520
2502
  </li>
2521
2503
  */}
2504
+
2505
+ {config.visualizationType === 'Forest Plot' && (
2506
+ <>
2507
+ <li>
2508
+ <label className='checkbox'>
2509
+ <input
2510
+ type='checkbox'
2511
+ checked={config.columns[val].forestPlot || false}
2512
+ onChange={event => {
2513
+ editColumn(val, 'forestPlot', event.target.checked)
2514
+ }}
2515
+ />
2516
+ <span className='edit-label'>Show in Forest Plot</span>
2517
+ </label>
2518
+ </li>
2519
+ <li>
2520
+ <label className='checkbox'>
2521
+ <input
2522
+ type='checkbox'
2523
+ checked={config.columns[val].tooltips || false}
2524
+ onChange={event => {
2525
+ updateSeriesTooltip(val, event.target.checked)
2526
+ }}
2527
+ />
2528
+ <span className='edit-label'>Show in tooltip</span>
2529
+ </label>
2530
+ </li>
2531
+ <li>
2532
+ <label className='checkbox'>
2533
+ <input
2534
+ type='checkbox'
2535
+ checked={config.columns[val].forestPlotAlignRight || false}
2536
+ onChange={event => {
2537
+ editColumn(val, 'forestPlotAlignRight', event.target.checked)
2538
+ }}
2539
+ />
2540
+ <span className='edit-label'>Align Right</span>
2541
+ </label>
2542
+ </li>
2543
+
2544
+ {!config.columns[val].forestPlotAlignRight && (
2545
+ <li>
2546
+ <label className='text'>
2547
+ <span className='edit-label'>Forest Plot Starting Point</span>
2548
+ <input
2549
+ type='number'
2550
+ value={config.columns[val].forestPlotStartingPoint || 0}
2551
+ onChange={event => {
2552
+ editColumn(val, 'forestPlotStartingPoint', event.target.value)
2553
+ }}
2554
+ />
2555
+ </label>
2556
+ </li>
2557
+ )}
2558
+ </>
2559
+ )}
2522
2560
  </ul>
2523
2561
  </fieldset>
2524
2562
  ))}
@@ -2651,15 +2689,16 @@ const EditorPanel = () => {
2651
2689
  </AccordionItemPanel>
2652
2690
  </AccordionItem>
2653
2691
  )}
2654
- <AccordionItem>
2655
- <AccordionItemHeading>
2656
- <AccordionItemButton>Filters</AccordionItemButton>
2657
- </AccordionItemHeading>
2658
- <AccordionItemPanel>
2659
- {config.filters && (
2660
- <>
2661
- {/* prettier-ignore */}
2662
- <Select
2692
+ {visSupportsFilters() && (
2693
+ <AccordionItem>
2694
+ <AccordionItemHeading>
2695
+ <AccordionItemButton>Filters</AccordionItemButton>
2696
+ </AccordionItemHeading>
2697
+ <AccordionItemPanel>
2698
+ {config.filters && (
2699
+ <>
2700
+ {/* prettier-ignore */}
2701
+ <Select
2663
2702
  value={config.filterBehavior}
2664
2703
  fieldName='filterBehavior'
2665
2704
  label='Filter Behavior'
@@ -2676,128 +2715,129 @@ const EditorPanel = () => {
2676
2715
  </Tooltip>
2677
2716
  }
2678
2717
  />
2679
- <br />
2680
- </>
2681
- )}
2682
- {config.filters && (
2683
- <ul className='filters-list'>
2684
- {/* Whether filters should apply onChange or Apply Button */}
2718
+ <br />
2719
+ </>
2720
+ )}
2721
+ {config.filters && (
2722
+ <ul className='filters-list'>
2723
+ {/* Whether filters should apply onChange or Apply Button */}
2685
2724
 
2686
- {config.filters.map((filter, index) => {
2687
- if (filter.type === 'url') return <></>
2725
+ {config.filters.map((filter, index) => {
2726
+ if (filter.type === 'url') return <></>
2688
2727
 
2689
- return (
2690
- <fieldset className='edit-block' key={index}>
2691
- <button
2692
- type='button'
2693
- className='remove-column'
2694
- onClick={() => {
2695
- removeFilter(index)
2696
- }}
2697
- >
2698
- Remove
2699
- </button>
2700
- <label>
2701
- <span className='edit-label column-heading'>Filter</span>
2702
- <select
2703
- value={filter.columnName}
2704
- onChange={e => {
2705
- updateFilterProp('columnName', index, e.target.value)
2728
+ return (
2729
+ <fieldset className='edit-block' key={index}>
2730
+ <button
2731
+ type='button'
2732
+ className='remove-column'
2733
+ onClick={() => {
2734
+ removeFilter(index)
2706
2735
  }}
2707
2736
  >
2708
- <option value=''>- Select Option -</option>
2709
- {getFilters(true).map((dataKey, index) => (
2710
- <option value={dataKey} key={index}>
2711
- {dataKey}
2712
- </option>
2713
- ))}
2714
- </select>
2715
- </label>
2737
+ Remove
2738
+ </button>
2739
+ <label>
2740
+ <span className='edit-label column-heading'>Filter</span>
2741
+ <select
2742
+ value={filter.columnName}
2743
+ onChange={e => {
2744
+ updateFilterProp('columnName', index, e.target.value)
2745
+ }}
2746
+ >
2747
+ <option value=''>- Select Option -</option>
2748
+ {getFilters(true).map((dataKey, index) => (
2749
+ <option value={dataKey} key={index}>
2750
+ {dataKey}
2751
+ </option>
2752
+ ))}
2753
+ </select>
2754
+ </label>
2716
2755
 
2717
- <label>
2718
- <span className='edit-showDropdown column-heading'>Show Filter Input</span>
2719
- <input
2720
- type='checkbox'
2721
- checked={filter.showDropdown === undefined ? true : filter.showDropdown}
2722
- onChange={e => {
2723
- updateFilterProp('showDropdown', index, e.target.checked)
2724
- }}
2725
- />
2726
- </label>
2756
+ <label>
2757
+ <span className='edit-showDropdown column-heading'>Show Filter Input</span>
2758
+ <input
2759
+ type='checkbox'
2760
+ checked={filter.showDropdown === undefined ? true : filter.showDropdown}
2761
+ onChange={e => {
2762
+ updateFilterProp('showDropdown', index, e.target.checked)
2763
+ }}
2764
+ />
2765
+ </label>
2727
2766
 
2728
- <label>
2729
- <span className='edit-label column-heading'>Filter Style</span>
2767
+ <label>
2768
+ <span className='edit-label column-heading'>Filter Style</span>
2730
2769
 
2731
- <select
2732
- value={filter.filterStyle}
2733
- onChange={e => {
2734
- updateFilterProp('filterStyle', index, e.target.value)
2735
- }}
2736
- >
2737
- {filterStyleOptions.map(item => {
2738
- return <option value={item}>{item}</option>
2739
- })}
2740
- </select>
2741
- </label>
2742
- <label>
2743
- <span className='edit-label column-heading'>Label</span>
2744
- <input
2745
- type='text'
2746
- value={filter.label}
2747
- onChange={e => {
2748
- updateFilterProp('label', index, e.target.value)
2749
- }}
2750
- />
2751
- </label>
2770
+ <select
2771
+ value={filter.filterStyle}
2772
+ onChange={e => {
2773
+ updateFilterProp('filterStyle', index, e.target.value)
2774
+ }}
2775
+ >
2776
+ {filterStyleOptions.map(item => {
2777
+ return <option value={item}>{item}</option>
2778
+ })}
2779
+ </select>
2780
+ </label>
2781
+ <label>
2782
+ <span className='edit-label column-heading'>Label</span>
2783
+ <input
2784
+ type='text'
2785
+ value={filter.label}
2786
+ onChange={e => {
2787
+ updateFilterProp('label', index, e.target.value)
2788
+ }}
2789
+ />
2790
+ </label>
2752
2791
 
2753
- <label>
2754
- <span className='edit-filterOrder column-heading'>Filter Order</span>
2755
- <select value={filter.order ? filter.order : 'asc'} onChange={e => updateFilterProp('order', index, e.target.value)}>
2756
- {filterOrderOptions.map((option, index) => {
2757
- return (
2758
- <option value={option.value} key={`filter-${index}`}>
2759
- {option.label}
2760
- </option>
2761
- )
2762
- })}
2763
- </select>
2792
+ <label>
2793
+ <span className='edit-filterOrder column-heading'>Filter Order</span>
2794
+ <select value={filter.order ? filter.order : 'asc'} onChange={e => updateFilterProp('order', index, e.target.value)}>
2795
+ {filterOrderOptions.map((option, index) => {
2796
+ return (
2797
+ <option value={option.value} key={`filter-${index}`}>
2798
+ {option.label}
2799
+ </option>
2800
+ )
2801
+ })}
2802
+ </select>
2764
2803
 
2765
- {filter.order === 'cust' && (
2766
- <DragDropContext onDragEnd={({ source, destination }) => handleFilterOrder(source.index, destination.index, index, config.filters[index])}>
2767
- <Droppable droppableId='filter_order'>
2768
- {provided => (
2769
- <ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
2770
- {config.filters[index]?.values.map((value, index) => {
2771
- return (
2772
- <Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
2773
- {(provided, snapshot) => (
2774
- <li>
2775
- <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
2776
- {value}
2777
- </div>
2778
- </li>
2779
- )}
2780
- </Draggable>
2781
- )
2782
- })}
2783
- {provided.placeholder}
2784
- </ul>
2785
- )}
2786
- </Droppable>
2787
- </DragDropContext>
2788
- )}
2789
- </label>
2790
- </fieldset>
2791
- )
2792
- })}
2793
- </ul>
2794
- )}
2795
- {!config.filters && <p style={{ textAlign: 'center' }}>There are currently no filters.</p>}
2796
- <button type='button' onClick={addNewFilter} className='btn full-width'>
2797
- Add Filter
2798
- </button>
2799
- </AccordionItemPanel>
2800
- </AccordionItem>
2804
+ {filter.order === 'cust' && (
2805
+ <DragDropContext onDragEnd={({ source, destination }) => handleFilterOrder(source.index, destination.index, index, config.filters[index])}>
2806
+ <Droppable droppableId='filter_order'>
2807
+ {provided => (
2808
+ <ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
2809
+ {config.filters[index]?.values.map((value, index) => {
2810
+ return (
2811
+ <Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
2812
+ {(provided, snapshot) => (
2813
+ <li>
2814
+ <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
2815
+ {value}
2816
+ </div>
2817
+ </li>
2818
+ )}
2819
+ </Draggable>
2820
+ )
2821
+ })}
2822
+ {provided.placeholder}
2823
+ </ul>
2824
+ )}
2825
+ </Droppable>
2826
+ </DragDropContext>
2827
+ )}
2828
+ </label>
2829
+ </fieldset>
2830
+ )
2831
+ })}
2832
+ </ul>
2833
+ )}
2834
+ {!config.filters && <p style={{ textAlign: 'center' }}>There are currently no filters.</p>}
2835
+ <button type='button' onClick={addNewFilter} className='btn full-width'>
2836
+ Add Filter
2837
+ </button>
2838
+ </AccordionItemPanel>
2839
+ </AccordionItem>
2840
+ )}
2801
2841
  <AccordionItem>
2802
2842
  <AccordionItemHeading>
2803
2843
  <AccordionItemButton>Visual</AccordionItemButton>
@@ -2863,77 +2903,85 @@ const EditorPanel = () => {
2863
2903
  ))}
2864
2904
  </ul>
2865
2905
  </label>
2866
- <label>
2867
- <span className='edit-label'>Chart Color Palette</span>
2868
- </label>
2869
2906
  {/* eslint-enable */}
2870
- {config.visualizationType !== 'Paired Bar' && config.visualizationType !== 'Deviation Bar' && (
2907
+ {(visSupportsNonSequentialPallete() || visSupportsNonSequentialPallete()) && (
2871
2908
  <>
2872
- <InputToggle fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={config.isPaletteReversed} />
2873
- <span>Sequential</span>
2874
- <ul className='color-palette'>
2875
- {sequential.map(palette => {
2876
- const colorOne = {
2877
- backgroundColor: colorPalettes[palette][2]
2878
- }
2909
+ <label>
2910
+ <span className='edit-label'>Chart Color Palette</span>
2911
+ </label>
2912
+ {visSupportsReverseColorPalette() && <InputToggle fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={config.isPaletteReversed} />}
2913
+ {visSupportsSequentialPallete() && (
2914
+ <>
2915
+ <span>Sequential</span>
2916
+ <ul className='color-palette'>
2917
+ {sequential.map(palette => {
2918
+ const colorOne = {
2919
+ backgroundColor: colorPalettes[palette][2]
2920
+ }
2879
2921
 
2880
- const colorTwo = {
2881
- backgroundColor: colorPalettes[palette][3]
2882
- }
2922
+ const colorTwo = {
2923
+ backgroundColor: colorPalettes[palette][3]
2924
+ }
2883
2925
 
2884
- const colorThree = {
2885
- backgroundColor: colorPalettes[palette][5]
2886
- }
2926
+ const colorThree = {
2927
+ backgroundColor: colorPalettes[palette][5]
2928
+ }
2887
2929
 
2888
- return (
2889
- <button
2890
- title={palette}
2891
- key={palette}
2892
- onClick={e => {
2893
- e.preventDefault()
2894
- updateConfig({ ...config, palette })
2895
- }}
2896
- className={config.palette === palette ? 'selected' : ''}
2897
- >
2898
- <span style={colorOne}></span>
2899
- <span style={colorTwo}></span>
2900
- <span style={colorThree}></span>
2901
- </button>
2902
- )
2903
- })}
2904
- </ul>
2905
- <span>Non-Sequential</span>
2906
- <ul className='color-palette'>
2907
- {nonSequential.map(palette => {
2908
- const colorOne = {
2909
- backgroundColor: colorPalettes[palette][2]
2910
- }
2930
+ return (
2931
+ <button
2932
+ title={palette}
2933
+ key={palette}
2934
+ onClick={e => {
2935
+ e.preventDefault()
2936
+ updateConfig({ ...config, palette })
2937
+ }}
2938
+ className={config.palette === palette ? 'selected' : ''}
2939
+ >
2940
+ <span style={colorOne}></span>
2941
+ <span style={colorTwo}></span>
2942
+ <span style={colorThree}></span>
2943
+ </button>
2944
+ )
2945
+ })}
2946
+ </ul>
2947
+ </>
2948
+ )}
2949
+ {visSupportsNonSequentialPallete() && (
2950
+ <>
2951
+ <span>Non-Sequential</span>
2952
+ <ul className='color-palette'>
2953
+ {nonSequential.map(palette => {
2954
+ const colorOne = {
2955
+ backgroundColor: colorPalettes[palette][2]
2956
+ }
2911
2957
 
2912
- const colorTwo = {
2913
- backgroundColor: colorPalettes[palette][4]
2914
- }
2958
+ const colorTwo = {
2959
+ backgroundColor: colorPalettes[palette][4]
2960
+ }
2915
2961
 
2916
- const colorThree = {
2917
- backgroundColor: colorPalettes[palette][6]
2918
- }
2962
+ const colorThree = {
2963
+ backgroundColor: colorPalettes[palette][6]
2964
+ }
2919
2965
 
2920
- return (
2921
- <button
2922
- title={palette}
2923
- key={palette}
2924
- onClick={e => {
2925
- e.preventDefault()
2926
- updateConfig({ ...config, palette })
2927
- }}
2928
- className={config.palette === palette ? 'selected' : ''}
2929
- >
2930
- <span style={colorOne}></span>
2931
- <span style={colorTwo}></span>
2932
- <span style={colorThree}></span>
2933
- </button>
2934
- )
2935
- })}
2936
- </ul>
2966
+ return (
2967
+ <button
2968
+ title={palette}
2969
+ key={palette}
2970
+ onClick={e => {
2971
+ e.preventDefault()
2972
+ updateConfig({ ...config, palette })
2973
+ }}
2974
+ className={config.palette === palette ? 'selected' : ''}
2975
+ >
2976
+ <span style={colorOne}></span>
2977
+ <span style={colorTwo}></span>
2978
+ <span style={colorThree}></span>
2979
+ </button>
2980
+ )
2981
+ })}
2982
+ </ul>
2983
+ </>
2984
+ )}
2937
2985
  </>
2938
2986
  )}
2939
2987
  {(config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') && (
@@ -2990,9 +3038,9 @@ const EditorPanel = () => {
2990
3038
  />
2991
3039
  </>
2992
3040
  )}
2993
- {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' />}
3041
+ {visSupportsBarThickness() && config.orientation === 'horizontal' && !config.isLollipopChart && config.yAxis.labelPlacement !== 'On Bar' && <TextField type='number' value={config.barHeight || '25'} fieldName='barHeight' label=' Bar Thickness' updateField={updateField} min='15' />}
2994
3042
  {((config.visualizationType === 'Bar' && config.orientation !== 'horizontal') || config.visualizationType === 'Combo') && <TextField value={config.barThickness} type='number' fieldName='barThickness' label='Bar Thickness' updateField={updateField} />}
2995
- {(config.orientation === 'horizontal' || config.visualizationType === 'Paired Bar') && <TextField type='number' value={config.barSpace || '15'} fieldName='barSpace' label='Bar Space' updateField={updateField} min='0' />}
3043
+ {visSupportsBarSpace() && <TextField type='number' value={config.barSpace || '15'} fieldName='barSpace' label='Bar Space' updateField={updateField} min='0' />}
2996
3044
  {(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} />}
2997
3045
 
2998
3046
  {config.visualizationType === 'Spark Line' && (