@cdc/chart 4.23.6 → 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 (48) hide show
  1. package/dist/cdcchart.js +29981 -29995
  2. package/examples/feature/__data__/area-chart-date-apple.json +5122 -0
  3. package/examples/feature/__data__/city-temperature.json +2198 -0
  4. package/examples/feature/__data__/planet-example-data.json +1 -1
  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/combo/right-issues.json +1 -1
  10. package/examples/feature/forecasting/combo-forecasting.json +72 -46
  11. package/examples/feature/forecasting/effective_reproduction.json +57 -8
  12. package/examples/feature/forecasting/forecasting.json +12 -3
  13. package/examples/feature/forest-plot/broken.json +700 -0
  14. package/examples/feature/forest-plot/data.csv +24 -0
  15. package/examples/feature/forest-plot/forest-plot.json +717 -0
  16. package/examples/feature/line/line-chart.json +11 -11
  17. package/examples/feature/pie/planet-pie-example-config.json +1 -1
  18. package/examples/gallery/bar-chart-vertical/vertical-bar-chart-categorical.json +167 -20
  19. package/examples/private/confidence_interval_test.json +248 -0
  20. package/examples/private/tooltip-issue.json +45275 -0
  21. package/index.html +13 -11
  22. package/package.json +4 -3
  23. package/src/CdcChart.jsx +78 -27
  24. package/src/components/AreaChart.jsx +65 -151
  25. package/src/components/BarChart.Horizontal.jsx +251 -0
  26. package/src/components/BarChart.StackedHorizontal.jsx +118 -0
  27. package/src/components/BarChart.StackedVertical.jsx +93 -0
  28. package/src/components/BarChart.Vertical.jsx +204 -0
  29. package/src/components/BarChart.jsx +17 -667
  30. package/src/components/BarChartType.jsx +15 -0
  31. package/src/components/BrushHandle.jsx +17 -0
  32. package/src/components/DataTable.jsx +67 -22
  33. package/src/components/EditorPanel.jsx +426 -358
  34. package/src/components/Forecasting.jsx +23 -86
  35. package/src/components/ForestPlot.jsx +191 -0
  36. package/src/components/ForestPlotSettings.jsx +508 -0
  37. package/src/components/Legend.jsx +10 -8
  38. package/src/components/LineChart.jsx +31 -6
  39. package/src/components/LinearChart.jsx +317 -230
  40. package/src/components/Series.jsx +40 -4
  41. package/src/data/initial-state.js +50 -3
  42. package/src/hooks/useBarChart.js +186 -0
  43. package/src/hooks/useEditorPermissions.js +218 -0
  44. package/src/hooks/useMinMax.js +18 -5
  45. package/src/hooks/useRightAxis.js +2 -1
  46. package/src/hooks/useScales.js +45 -2
  47. package/src/hooks/useTooltip.jsx +407 -0
  48. package/src/scss/main.scss +11 -17
@@ -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'
@@ -412,7 +450,18 @@ const EditorPanel = () => {
412
450
 
413
451
  const addNewSeries = seriesKey => {
414
452
  let newSeries = config.series ? [...config.series] : []
415
- newSeries.push({ dataKey: seriesKey, type: config.visualizationType })
453
+ let forecastingStages = Array.from(new Set(data.map(item => item[seriesKey])))
454
+ let forecastingStageArr = []
455
+
456
+ forecastingStages.forEach(stage => {
457
+ forecastingStageArr.push({ key: stage })
458
+ })
459
+
460
+ if (config.visualizationType === 'Forecasting') {
461
+ newSeries.push({ dataKey: seriesKey, type: config.visualizationType, stages: forecastingStageArr, stageColumn: seriesKey, axis: 'Left', tooltip: true })
462
+ } else {
463
+ newSeries.push({ dataKey: seriesKey, type: config.visualizationType, axis: 'Left', tooltip: true })
464
+ }
416
465
  updateConfig({ ...config, series: newSeries }) // left axis series keys
417
466
  }
418
467
 
@@ -670,91 +719,6 @@ const EditorPanel = () => {
670
719
  )
671
720
  }, [config]) // eslint-disable-line
672
721
 
673
- const visSupportsTooltipLines = () => {
674
- if (config.visualizationType === 'Combo' && config.runtime.forecastingSeriesKeys?.length > 0) return true
675
- if (config.visualizationType === 'Forecasting') return true
676
- return false
677
- }
678
-
679
- const visHasLegend = () => {
680
- const { visualizationType } = config
681
-
682
- switch (visualizationType) {
683
- case 'Box Plot':
684
- return false
685
- default:
686
- return true
687
- }
688
- }
689
-
690
- const visCanAnimate = () => {
691
- const { visualizationType } = config
692
- switch (visualizationType) {
693
- case 'Area Chart':
694
- return false
695
- case 'Scatter Plot':
696
- return false
697
- case 'Box Plot':
698
- return false
699
- default:
700
- return true
701
- }
702
- }
703
-
704
- const visHasDataCutoff = () => {
705
- const { visualizationType } = config
706
- switch (visualizationType) {
707
- case 'Box Plot':
708
- return false
709
- case 'Pie':
710
- return false
711
- default:
712
- return true
713
- }
714
- }
715
-
716
- const visHasLabelOnData = () => {
717
- const { visualizationType } = config
718
- switch (visualizationType) {
719
- case 'Area Chart':
720
- return false
721
- case 'Box Plot':
722
- return false
723
- case 'Pie':
724
- return false
725
- case 'Scatter Plot':
726
- return false
727
- default:
728
- return true
729
- }
730
- }
731
-
732
- const visHasAnchors = () => {
733
- const { visualizationType } = config
734
- switch (visualizationType) {
735
- case 'Area Chart':
736
- return true
737
- case 'Combo':
738
- return true
739
- case 'Line':
740
- return true
741
- case 'Bar':
742
- return true
743
- case 'Scatter Plot':
744
- return true
745
- default:
746
- return false
747
- }
748
- }
749
-
750
- const visHasBarBorders = () => {
751
- const { series, visualizationType } = config
752
- if (visualizationType === 'Box Plot') return false
753
- if (visualizationType === 'Scatter Plot') return false
754
- if (visualizationType === 'Pie') return false
755
- return series?.some(series => series.type === 'Bar' || series.type === 'Paired Bar' || series.type === 'Deviation Bar')
756
- }
757
-
758
722
  const handleSeriesChange = (idx1, idx2) => {
759
723
  let seriesOrder = config.series
760
724
  let [movedItem] = seriesOrder.splice(idx1, 1)
@@ -765,6 +729,9 @@ const EditorPanel = () => {
765
729
  if (config.isLollipopChart && config?.series?.length > 1) {
766
730
  config.runtime.editorErrorMessage = 'Lollipop charts must use only one data series'
767
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
+ }
768
735
 
769
736
  if (config.isLollipopChart && config?.series?.length === 0) {
770
737
  config.runtime.editorErrorMessage = 'Add a data series'
@@ -824,21 +791,6 @@ const EditorPanel = () => {
824
791
  validateMaxValue()
825
792
  }, [minValue, maxValue, config]) // eslint-disable-line
826
793
 
827
- // prettier-ignore
828
- const enabledChartTypes = [
829
- 'Area Chart',
830
- 'Bar',
831
- 'Box Plot',
832
- 'Combo',
833
- 'Deviation Bar',
834
- // 'Forecasting',
835
- 'Line',
836
- 'Paired Bar',
837
- 'Pie',
838
- 'Scatter Plot',
839
- 'Spark Line'
840
- ]
841
-
842
794
  const isLoadedFromUrl = config?.dataKey?.includes('http://') || config?.dataKey?.includes('https://')
843
795
 
844
796
  // if isDebug = true, then try to set the category and data col to reduce clicking
@@ -883,7 +835,7 @@ const EditorPanel = () => {
883
835
  if (config.data && config.series) {
884
836
  Object.keys(config.data[0]).map(colName => {
885
837
  // OMIT ANY COLUMNS THAT ARE IN DATA SERIES!
886
- const found = config?.series.some(el => el.dataKey === colName)
838
+ const found = config?.series.some(series => series.dataKey === colName)
887
839
  if (colName !== config.xAxis.dataKey && !found) {
888
840
  // if not the index then add it
889
841
  return columnsOptions.push(
@@ -959,7 +911,10 @@ const EditorPanel = () => {
959
911
  dataTable: false,
960
912
  tooltips: false,
961
913
  prefix: '',
962
- suffix: ''
914
+ suffix: '',
915
+ forestPlot: false,
916
+ startingPoint: '0',
917
+ forestPlotAlignRight: false
963
918
  }
964
919
  }
965
920
  })
@@ -1018,6 +973,21 @@ const EditorPanel = () => {
1018
973
  handleUpdateHighlightedBorderWidth
1019
974
  } = useHighlightedBars(config, updateConfig)
1020
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
+
1021
991
  return (
1022
992
  <ErrorBoundary component='EditorPanel'>
1023
993
  {config.newViz && <Confirm />}
@@ -1046,7 +1016,7 @@ const EditorPanel = () => {
1046
1016
  <Select value={config.roundingStyle || 'standard'} fieldName='roundingStyle' label='rounding style' updateField={updateField} options={['standard', 'shallow', 'finger']} />
1047
1017
  )}
1048
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']} />}
1049
- {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() ? (
1050
1020
  <CheckBox value={config.yAxis.displayNumbersOnBar} section='yAxis' fieldName='displayNumbersOnBar' label={config.isLollipopChart ? 'Display Numbers after Bar' : 'Display Numbers on Bar'} updateField={updateField} />
1051
1021
  ) : (
1052
1022
  visHasLabelOnData() && <CheckBox value={config.labels} fieldName='labels' label='Display label on data' updateField={updateField} />
@@ -1149,7 +1119,8 @@ const EditorPanel = () => {
1149
1119
  {config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
1150
1120
  </AccordionItemPanel>
1151
1121
  </AccordionItem>
1152
- {config.visualizationType !== 'Pie' && (
1122
+ {config.visualizationType === 'Forest Plot' && <ForestPlotSettings />}
1123
+ {config.visualizationType !== 'Pie' && config.visualizationType !== 'Forest Plot' && (
1153
1124
  <AccordionItem>
1154
1125
  <AccordionItemHeading>
1155
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,54 +1316,13 @@ const EditorPanel = () => {
1345
1316
  <TextField type='text' value={config.boxplot.labels.outliers} fieldName='outliers' section='boxplot' subsection='labels' label='Outliers' updateField={updateField} />
1346
1317
  {/* values */}
1347
1318
  <TextField type='text' value={config.boxplot.labels.values} fieldName='values' section='boxplot' subsection='labels' label='Values' updateField={updateField} />
1348
- <br />
1349
- <h4 style={{ fontSize: '18px' }}>Percentages for Quartiles</h4>
1350
- <TextField
1351
- type='number'
1352
- value={config.boxplot.firstQuartilePercentage ? config.boxplot.firstQuartilePercentage : 25}
1353
- fieldName='firstQuartilePercentage'
1354
- section='boxplot'
1355
- label='Lower Quartile'
1356
- max={100}
1357
- updateField={updateField}
1358
- tooltip={
1359
- <Tooltip style={{ textTransform: 'none' }}>
1360
- <Tooltip.Target>
1361
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1362
- </Tooltip.Target>
1363
- <Tooltip.Content>
1364
- <p>Represented by bottom line of box. 25% of data are lower.</p>
1365
- </Tooltip.Content>
1366
- </Tooltip>
1367
- }
1368
- />
1369
-
1370
- <TextField
1371
- type='number'
1372
- value={config.boxplot.thirdQuartilePercentage ? config.boxplot.thirdQuartilePercentage : 75}
1373
- fieldName='thirdQuartilePercentage'
1374
- label='Upper Quartile'
1375
- section='boxplot'
1376
- max={100}
1377
- updateField={updateField}
1378
- tooltip={
1379
- <Tooltip style={{ textTransform: 'none' }}>
1380
- <Tooltip.Target>
1381
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1382
- </Tooltip.Target>
1383
- <Tooltip.Content>
1384
- <p>Represented by top line of box. 25% of data are higher.</p>
1385
- </Tooltip.Content>
1386
- </Tooltip>
1387
- }
1388
- />
1389
1319
  </AccordionItemPanel>
1390
1320
  </AccordionItem>
1391
1321
  )}
1392
1322
  <AccordionItem>
1393
1323
  <AccordionItemHeading>
1394
1324
  <AccordionItemButton>
1395
- {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'}
1396
1326
  {config.visualizationType === 'Pie' && !config.yAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1397
1327
  </AccordionItemButton>
1398
1328
  </AccordionItemHeading>
@@ -1444,10 +1374,35 @@ const EditorPanel = () => {
1444
1374
  </Tooltip>
1445
1375
  }
1446
1376
  />
1377
+ {config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' updateField={updateField} />}
1378
+ {(config.orientation === 'vertical' || !config.isResponsiveTicks) && <TextField value={config.yAxis.tickRotation} type='number' min='0' section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1379
+ {config.isResponsiveTicks && config.orientation === 'horizontal' && config.visualizationType !== 'Paired Bar' && (
1380
+ <TextField
1381
+ value={config.xAxis.maxTickRotation}
1382
+ type='number'
1383
+ min='0'
1384
+ section='xAxis'
1385
+ fieldName='maxTickRotation'
1386
+ label='Max Tick Rotation'
1387
+ className='number-narrow'
1388
+ updateField={updateField}
1389
+ tooltip={
1390
+ <Tooltip style={{ textTransform: 'none' }}>
1391
+ <Tooltip.Target>
1392
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1393
+ </Tooltip.Target>
1394
+ <Tooltip.Content>
1395
+ <p>Degrees ticks will be rotated if values overlap, especially in smaller viewports.</p>
1396
+ </Tooltip.Content>
1397
+ </Tooltip>
1398
+ }
1399
+ />
1400
+ )}
1401
+
1447
1402
  {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
1448
1403
  {/* <TextField value={config.yAxis.axisPadding} type='number' max={10} min={0} section='yAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
1449
1404
  {config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
1450
- {config.orientation !== 'horizontal' && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Display Gridlines' updateField={updateField} />}
1405
+ {visSupportsValueAxisGridLines() && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Show Gridlines' updateField={updateField} />}
1451
1406
  <CheckBox value={config.yAxis.enablePadding} section='yAxis' fieldName='enablePadding' label='Add Padding to Value Axis Scale' updateField={updateField} />
1452
1407
  {config.visualizationSubType === 'regular' && <CheckBox value={config.useLogScale} fieldName='useLogScale' label='use logarithmic scale' updateField={updateField} />}
1453
1408
  </>
@@ -1513,9 +1468,9 @@ const EditorPanel = () => {
1513
1468
 
1514
1469
  {config.orientation === 'horizontal' ? ( // horizontal - x is vertical y is horizontal
1515
1470
  <>
1516
- <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1517
- <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1518
- <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} />}
1519
1474
  <TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='max value' type='number' placeholder='Auto' updateField={updateField} />
1520
1475
  <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1521
1476
  <TextField value={config.xAxis.min} section='xAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />
@@ -1524,7 +1479,7 @@ const EditorPanel = () => {
1524
1479
  <>
1525
1480
  <TextField value={config.xAxis.target} section='xAxis' fieldName='target' type='number' label='Deviation point' placeholder='Auto' updateField={updateField} />
1526
1481
  <TextField value={config.xAxis.targetLabel || 'Target'} section='xAxis' fieldName='targetLabel' type='text' label='Deviation point Label' updateField={updateField} />
1527
- <CheckBox value={config.xAxis.showTargetLabel} section='xAxis' fieldName='showTargetLabel' label='Display Deviation point label' updateField={updateField} />
1482
+ <CheckBox value={config.xAxis.showTargetLabel} section='xAxis' fieldName='showTargetLabel' label='Show Deviation point label' updateField={updateField} />
1528
1483
  </>
1529
1484
  )}
1530
1485
  </>
@@ -1546,10 +1501,10 @@ const EditorPanel = () => {
1546
1501
  {/* start: anchors */}
1547
1502
  {visHasAnchors() && config.orientation !== 'horizontal' && (
1548
1503
  <div className='edit-block'>
1549
- <h3>Anchors</h3>
1504
+ <span className='edit-label column-heading'>Anchors</span>
1550
1505
  <Accordion allowZeroExpanded>
1551
1506
  {config.yAxis?.anchors?.map((anchor, index) => (
1552
- <AccordionItem className='series-item series-item--chart'>
1507
+ <AccordionItem className='series-item series-item--chart' key={`yaxis-anchors-2-${index}`}>
1553
1508
  <AccordionItemHeading className='series-item__title'>
1554
1509
  <>
1555
1510
  <AccordionItemButton className={'accordion__button accordion__button'}>
@@ -1672,10 +1627,10 @@ const EditorPanel = () => {
1672
1627
 
1673
1628
  {visHasAnchors() && config.orientation === 'horizontal' && (
1674
1629
  <div className='edit-block'>
1675
- <h3>Anchors</h3>
1630
+ <span className='edit-label column-heading'>Anchors</span>
1676
1631
  <Accordion allowZeroExpanded>
1677
1632
  {config.xAxis?.anchors?.map((anchor, index) => (
1678
- <AccordionItem className='series-item series-item--chart'>
1633
+ <AccordionItem className='series-item series-item--chart' key={`xaxis-anchors-${index}`}>
1679
1634
  <AccordionItemHeading className='series-item__title'>
1680
1635
  <>
1681
1636
  <AccordionItemButton className={'accordion__button accordion__button'}>
@@ -1861,14 +1816,16 @@ const EditorPanel = () => {
1861
1816
  <AccordionItem>
1862
1817
  <AccordionItemHeading>
1863
1818
  <AccordionItemButton>
1864
- {config.visualizationType !== 'Pie' ? (config.visualizationType === 'Bar' ? 'Date/Category Axis' : 'Date/Category Axis') : 'Segments'}
1819
+ {config.visualizationType === 'Pie' ? 'Segments' : 'Date/Category Axis'}
1865
1820
  {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1866
1821
  </AccordionItemButton>
1867
1822
  </AccordionItemHeading>
1868
1823
  <AccordionItemPanel>
1869
1824
  {config.visualizationType !== 'Pie' && (
1870
1825
  <>
1871
- <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
+ )}
1872
1829
  <Select
1873
1830
  value={config.xAxis.dataKey || setCategoryAxis() || ''}
1874
1831
  section='xAxis'
@@ -2047,7 +2004,8 @@ const EditorPanel = () => {
2047
2004
  )}
2048
2005
  </>
2049
2006
  )}
2050
- <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} />}
2051
2009
 
2052
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} />
2053
2011
 
@@ -2060,12 +2018,37 @@ const EditorPanel = () => {
2060
2018
  <TextField value={config.dataFormat.bottomRoundTo} type='number' section='dataFormat' fieldName='bottomRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
2061
2019
  </>
2062
2020
  )}
2021
+ {config.orientation === 'vertical' && config.visualizationType !== 'Paired Bar' && <CheckBox value={config.isResponsiveTicks} fieldName='isResponsiveTicks' label='Use Responsive Ticks' 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
+ )}
2025
+ {config.orientation === 'vertical' && config.isResponsiveTicks && config.visualizationType !== 'Paired Bar' && (
2026
+ <TextField
2027
+ value={config.xAxis.maxTickRotation}
2028
+ type='number'
2029
+ min='0'
2030
+ section='xAxis'
2031
+ fieldName='maxTickRotation'
2032
+ label='Max Tick Rotation'
2033
+ className='number-narrow'
2034
+ updateField={updateField}
2035
+ tooltip={
2036
+ <Tooltip style={{ textTransform: 'none' }}>
2037
+ <Tooltip.Target>
2038
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2039
+ </Tooltip.Target>
2040
+ <Tooltip.Content>
2041
+ <p>Degrees ticks will be rotated if values overlap, especially in smaller viewports.</p>
2042
+ </Tooltip.Content>
2043
+ </Tooltip>
2044
+ }
2045
+ />
2046
+ )}
2063
2047
 
2064
- {config.yAxis.labelPlacement !== 'Below Bar' && <TextField value={config.xAxis.tickRotation} type='number' min='0' section='xAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
2065
2048
  {config.orientation === 'horizontal' ? (
2066
2049
  <>
2067
- <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
2068
- <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} />}
2069
2052
  </>
2070
2053
  ) : (
2071
2054
  <>
@@ -2167,10 +2150,10 @@ const EditorPanel = () => {
2167
2150
  {/* anchors */}
2168
2151
  {visHasAnchors() && config.orientation !== 'horizontal' && (
2169
2152
  <div className='edit-block'>
2170
- <h3>Anchors</h3>
2153
+ <span className='edit-label column-heading'>Anchors</span>
2171
2154
  <Accordion allowZeroExpanded>
2172
2155
  {config.xAxis?.anchors?.map((anchor, index) => (
2173
- <AccordionItem className='series-item series-item--chart'>
2156
+ <AccordionItem className='series-item series-item--chart' key={`xaxis-anchors-2-${index}`}>
2174
2157
  <AccordionItemHeading className='series-item__title'>
2175
2158
  <>
2176
2159
  <AccordionItemButton className={'accordion__button accordion__button'}>
@@ -2293,10 +2276,10 @@ const EditorPanel = () => {
2293
2276
 
2294
2277
  {visHasAnchors() && config.orientation === 'horizontal' && (
2295
2278
  <div className='edit-block'>
2296
- <h3>Anchors</h3>
2279
+ <span className='edit-label column-heading'>Anchors</span>
2297
2280
  <Accordion allowZeroExpanded>
2298
2281
  {config.yAxis?.anchors?.map((anchor, index) => (
2299
- <AccordionItem className='series-item series-item--chart'>
2282
+ <AccordionItem className='series-item series-item--chart' key={`accordion-yaxis-anchors-${index}`}>
2300
2283
  <AccordionItemHeading className='series-item__title'>
2301
2284
  <>
2302
2285
  <AccordionItemButton className={'accordion__button accordion__button'}>
@@ -2418,7 +2401,7 @@ const EditorPanel = () => {
2418
2401
  )}
2419
2402
  </AccordionItemPanel>
2420
2403
  </AccordionItem>
2421
- {config.visualizationType !== 'Pie' && config.visualizationType !== 'Paired Bar' && (
2404
+ {visSupportsRegions() && (
2422
2405
  <AccordionItem>
2423
2406
  <AccordionItemHeading>
2424
2407
  <AccordionItemButton>Regions</AccordionItemButton>
@@ -2483,9 +2466,9 @@ const EditorPanel = () => {
2483
2466
  <label className='checkbox'>
2484
2467
  <input
2485
2468
  type='checkbox'
2486
- checked={config.columns[val].useCommas}
2469
+ checked={config.columns[val].commas}
2487
2470
  onChange={event => {
2488
- editColumn(val, 'useCommas', event.target.checked)
2471
+ editColumn(val, 'commas', event.target.checked)
2489
2472
  }}
2490
2473
  />
2491
2474
  <span className='edit-label'>Add Commas to Numbers</span>
@@ -2500,7 +2483,7 @@ const EditorPanel = () => {
2500
2483
  editColumn(val, 'dataTable', event.target.checked)
2501
2484
  }}
2502
2485
  />
2503
- <span className='edit-label'>Display in Data Table</span>
2486
+ <span className='edit-label'>Show in Data Table</span>
2504
2487
  </label>
2505
2488
  </li>
2506
2489
  {/* disable for now */}
@@ -2518,6 +2501,62 @@ const EditorPanel = () => {
2518
2501
  </label>
2519
2502
  </li>
2520
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
+ )}
2521
2560
  </ul>
2522
2561
  </fieldset>
2523
2562
  ))}
@@ -2650,15 +2689,16 @@ const EditorPanel = () => {
2650
2689
  </AccordionItemPanel>
2651
2690
  </AccordionItem>
2652
2691
  )}
2653
- <AccordionItem>
2654
- <AccordionItemHeading>
2655
- <AccordionItemButton>Filters</AccordionItemButton>
2656
- </AccordionItemHeading>
2657
- <AccordionItemPanel>
2658
- {config.filters && (
2659
- <>
2660
- {/* prettier-ignore */}
2661
- <Select
2692
+ {visSupportsFilters() && (
2693
+ <AccordionItem>
2694
+ <AccordionItemHeading>
2695
+ <AccordionItemButton>Filters</AccordionItemButton>
2696
+ </AccordionItemHeading>
2697
+ <AccordionItemPanel>
2698
+ {config.filters && (
2699
+ <>
2700
+ {/* prettier-ignore */}
2701
+ <Select
2662
2702
  value={config.filterBehavior}
2663
2703
  fieldName='filterBehavior'
2664
2704
  label='Filter Behavior'
@@ -2675,128 +2715,129 @@ const EditorPanel = () => {
2675
2715
  </Tooltip>
2676
2716
  }
2677
2717
  />
2678
- <br />
2679
- </>
2680
- )}
2681
- {config.filters && (
2682
- <ul className='filters-list'>
2683
- {/* 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 */}
2684
2724
 
2685
- {config.filters.map((filter, index) => {
2686
- if (filter.type === 'url') return <></>
2725
+ {config.filters.map((filter, index) => {
2726
+ if (filter.type === 'url') return <></>
2687
2727
 
2688
- return (
2689
- <fieldset className='edit-block' key={index}>
2690
- <button
2691
- type='button'
2692
- className='remove-column'
2693
- onClick={() => {
2694
- removeFilter(index)
2695
- }}
2696
- >
2697
- Remove
2698
- </button>
2699
- <label>
2700
- <span className='edit-label column-heading'>Filter</span>
2701
- <select
2702
- value={filter.columnName}
2703
- onChange={e => {
2704
- 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)
2705
2735
  }}
2706
2736
  >
2707
- <option value=''>- Select Option -</option>
2708
- {getFilters(true).map((dataKey, index) => (
2709
- <option value={dataKey} key={index}>
2710
- {dataKey}
2711
- </option>
2712
- ))}
2713
- </select>
2714
- </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>
2715
2755
 
2716
- <label>
2717
- <span className='edit-showDropdown column-heading'>Show Filter Input</span>
2718
- <input
2719
- type='checkbox'
2720
- checked={filter.showDropdown === undefined ? true : filter.showDropdown}
2721
- onChange={e => {
2722
- updateFilterProp('showDropdown', index, e.target.checked)
2723
- }}
2724
- />
2725
- </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>
2726
2766
 
2727
- <label>
2728
- <span className='edit-label column-heading'>Filter Style</span>
2767
+ <label>
2768
+ <span className='edit-label column-heading'>Filter Style</span>
2729
2769
 
2730
- <select
2731
- value={filter.filterStyle}
2732
- onChange={e => {
2733
- updateFilterProp('filterStyle', index, e.target.value)
2734
- }}
2735
- >
2736
- {filterStyleOptions.map(item => {
2737
- return <option value={item}>{item}</option>
2738
- })}
2739
- </select>
2740
- </label>
2741
- <label>
2742
- <span className='edit-label column-heading'>Label</span>
2743
- <input
2744
- type='text'
2745
- value={filter.label}
2746
- onChange={e => {
2747
- updateFilterProp('label', index, e.target.value)
2748
- }}
2749
- />
2750
- </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>
2751
2791
 
2752
- <label>
2753
- <span className='edit-filterOrder column-heading'>Filter Order</span>
2754
- <select value={filter.order ? filter.order : 'asc'} onChange={e => updateFilterProp('order', index, e.target.value)}>
2755
- {filterOrderOptions.map((option, index) => {
2756
- return (
2757
- <option value={option.value} key={`filter-${index}`}>
2758
- {option.label}
2759
- </option>
2760
- )
2761
- })}
2762
- </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>
2763
2803
 
2764
- {filter.order === 'cust' && (
2765
- <DragDropContext onDragEnd={({ source, destination }) => handleFilterOrder(source.index, destination.index, index, config.filters[index])}>
2766
- <Droppable droppableId='filter_order'>
2767
- {provided => (
2768
- <ul {...provided.droppableProps} className='sort-list' ref={provided.innerRef} style={{ marginTop: '1em' }}>
2769
- {config.filters[index]?.values.map((value, index) => {
2770
- return (
2771
- <Draggable key={value} draggableId={`draggableFilter-${value}`} index={index}>
2772
- {(provided, snapshot) => (
2773
- <li>
2774
- <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
2775
- {value}
2776
- </div>
2777
- </li>
2778
- )}
2779
- </Draggable>
2780
- )
2781
- })}
2782
- {provided.placeholder}
2783
- </ul>
2784
- )}
2785
- </Droppable>
2786
- </DragDropContext>
2787
- )}
2788
- </label>
2789
- </fieldset>
2790
- )
2791
- })}
2792
- </ul>
2793
- )}
2794
- {!config.filters && <p style={{ textAlign: 'center' }}>There are currently no filters.</p>}
2795
- <button type='button' onClick={addNewFilter} className='btn full-width'>
2796
- Add Filter
2797
- </button>
2798
- </AccordionItemPanel>
2799
- </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
+ )}
2800
2841
  <AccordionItem>
2801
2842
  <AccordionItemHeading>
2802
2843
  <AccordionItemButton>Visual</AccordionItemButton>
@@ -2862,77 +2903,85 @@ const EditorPanel = () => {
2862
2903
  ))}
2863
2904
  </ul>
2864
2905
  </label>
2865
- <label>
2866
- <span className='edit-label'>Chart Color Palette</span>
2867
- </label>
2868
2906
  {/* eslint-enable */}
2869
- {config.visualizationType !== 'Paired Bar' && config.visualizationType !== 'Deviation Bar' && (
2907
+ {(visSupportsNonSequentialPallete() || visSupportsNonSequentialPallete()) && (
2870
2908
  <>
2871
- <InputToggle fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={config.isPaletteReversed} />
2872
- <span>Sequential</span>
2873
- <ul className='color-palette'>
2874
- {sequential.map(palette => {
2875
- const colorOne = {
2876
- backgroundColor: colorPalettes[palette][2]
2877
- }
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
+ }
2878
2921
 
2879
- const colorTwo = {
2880
- backgroundColor: colorPalettes[palette][3]
2881
- }
2922
+ const colorTwo = {
2923
+ backgroundColor: colorPalettes[palette][3]
2924
+ }
2882
2925
 
2883
- const colorThree = {
2884
- backgroundColor: colorPalettes[palette][5]
2885
- }
2926
+ const colorThree = {
2927
+ backgroundColor: colorPalettes[palette][5]
2928
+ }
2886
2929
 
2887
- return (
2888
- <button
2889
- title={palette}
2890
- key={palette}
2891
- onClick={e => {
2892
- e.preventDefault()
2893
- updateConfig({ ...config, palette })
2894
- }}
2895
- className={config.palette === palette ? 'selected' : ''}
2896
- >
2897
- <span style={colorOne}></span>
2898
- <span style={colorTwo}></span>
2899
- <span style={colorThree}></span>
2900
- </button>
2901
- )
2902
- })}
2903
- </ul>
2904
- <span>Non-Sequential</span>
2905
- <ul className='color-palette'>
2906
- {nonSequential.map(palette => {
2907
- const colorOne = {
2908
- backgroundColor: colorPalettes[palette][2]
2909
- }
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
+ }
2910
2957
 
2911
- const colorTwo = {
2912
- backgroundColor: colorPalettes[palette][4]
2913
- }
2958
+ const colorTwo = {
2959
+ backgroundColor: colorPalettes[palette][4]
2960
+ }
2914
2961
 
2915
- const colorThree = {
2916
- backgroundColor: colorPalettes[palette][6]
2917
- }
2962
+ const colorThree = {
2963
+ backgroundColor: colorPalettes[palette][6]
2964
+ }
2918
2965
 
2919
- return (
2920
- <button
2921
- title={palette}
2922
- key={palette}
2923
- onClick={e => {
2924
- e.preventDefault()
2925
- updateConfig({ ...config, palette })
2926
- }}
2927
- className={config.palette === palette ? 'selected' : ''}
2928
- >
2929
- <span style={colorOne}></span>
2930
- <span style={colorTwo}></span>
2931
- <span style={colorThree}></span>
2932
- </button>
2933
- )
2934
- })}
2935
- </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
+ )}
2936
2985
  </>
2937
2986
  )}
2938
2987
  {(config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') && (
@@ -2989,14 +3038,14 @@ const EditorPanel = () => {
2989
3038
  />
2990
3039
  </>
2991
3040
  )}
2992
- {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' />}
2993
3042
  {((config.visualizationType === 'Bar' && config.orientation !== 'horizontal') || config.visualizationType === 'Combo') && <TextField value={config.barThickness} type='number' fieldName='barThickness' label='Bar Thickness' updateField={updateField} />}
2994
- {(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' />}
2995
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} />}
2996
3045
 
2997
3046
  {config.visualizationType === 'Spark Line' && (
2998
3047
  <div className='cove-accordion__panel-section checkbox-group'>
2999
- <CheckBox value={config.visual?.border} section='visual' fieldName='border' label='Display Border' updateField={updateField} />
3048
+ <CheckBox value={config.visual?.border} section='visual' fieldName='border' label='Show Border' updateField={updateField} />
3000
3049
  <CheckBox value={config.visual?.borderColorTheme} section='visual' fieldName='borderColorTheme' label='Use Border Color Theme' updateField={updateField} />
3001
3050
  <CheckBox value={config.visual?.accent} section='visual' fieldName='accent' label='Use Accent Style' updateField={updateField} />
3002
3051
  <CheckBox value={config.visual?.background} section='visual' fieldName='background' label='Use Theme Background Color' updateField={updateField} />
@@ -3015,6 +3064,25 @@ const EditorPanel = () => {
3015
3064
  <CheckBox value={config.visual.horizontalHoverLine} fieldName='horizontalHoverLine' section='visual' label='Horizontal Hover Line' updateField={updateField} />
3016
3065
  </>
3017
3066
  )}
3067
+
3068
+ {
3069
+ <label>
3070
+ <span className='edit-label column-heading'>Tooltip Opacity</span>
3071
+ <input
3072
+ type='number'
3073
+ value={config.tooltips.opacity ? config.tooltips.opacity : 100}
3074
+ onChange={e =>
3075
+ updateConfig({
3076
+ ...config,
3077
+ tooltips: {
3078
+ ...config.tooltips,
3079
+ opacity: e.target.value
3080
+ }
3081
+ })
3082
+ }
3083
+ />
3084
+ </label>
3085
+ }
3018
3086
  </AccordionItemPanel>
3019
3087
  </AccordionItem>
3020
3088
  {/* Spark Line has no data table */}