@cdc/chart 4.23.4 → 4.23.6

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 (42) hide show
  1. package/dist/cdcchart.js +54845 -51755
  2. package/examples/feature/__data__/planet-example-data.json +14 -32
  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/new.json +561 -0
  7. package/examples/feature/bar/planet-chart-logaritmic-config.json +170 -0
  8. package/examples/feature/boxplot/valid-boxplot.csv +17 -0
  9. package/examples/feature/combo/right-issues.json +190 -0
  10. package/examples/feature/filters/filter-testing.json +37 -3
  11. package/examples/feature/forecasting/combo-forecasting.json +245 -0
  12. package/examples/feature/forecasting/forecasting.json +5325 -0
  13. package/examples/feature/forecasting/index.json +203 -0
  14. package/examples/feature/forecasting/random_data.csv +366 -0
  15. package/examples/feature/line/line-chart.json +3 -3
  16. package/examples/feature/test-highlight/test-highlight-2.json +789 -0
  17. package/examples/feature/test-highlight/test-highlight-vertical.json +561 -0
  18. package/examples/feature/test-highlight/test-highlight.json +100 -0
  19. package/examples/feature/tests-non-numerics/stacked-vertical-bar-example-nonnumerics.json +1 -2
  20. package/examples/gallery/bar-chart-horizontal/horizontal-highlight.json +345 -0
  21. package/examples/gallery/line/line.json +173 -1
  22. package/index.html +14 -8
  23. package/package.json +2 -2
  24. package/src/CdcChart.jsx +342 -25
  25. package/src/components/AreaChart.jsx +32 -40
  26. package/src/components/BarChart.jsx +147 -25
  27. package/src/components/DataTable.jsx +30 -12
  28. package/src/components/DeviationBar.jsx +32 -32
  29. package/src/components/EditorPanel.jsx +1902 -1126
  30. package/src/components/Forecasting.jsx +147 -0
  31. package/src/components/Legend.jsx +193 -243
  32. package/src/components/LineChart.jsx +4 -9
  33. package/src/components/LinearChart.jsx +263 -285
  34. package/src/components/Series.jsx +518 -0
  35. package/src/components/SparkLine.jsx +3 -3
  36. package/src/data/initial-state.js +24 -5
  37. package/src/hooks/useHighlightedBars.js +154 -0
  38. package/src/hooks/useMinMax.js +128 -0
  39. package/src/hooks/useReduceData.js +31 -57
  40. package/src/hooks/useRightAxis.js +8 -2
  41. package/src/hooks/useScales.js +196 -0
  42. /package/examples/feature/area/{area-chart.json → area-chart-date.json} +0 -0
@@ -17,8 +17,9 @@ 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 Series from './Series'
22
+ import { useHighlightedBars } from '../hooks/useHighlightedBars'
22
23
 
23
24
  /* eslint-disable react-hooks/rules-of-hooks */
24
25
  const TextField = memo(({ label, tooltip, section = null, subsection = null, fieldName, updateField, value: stateValue, type = 'input', i = null, min = null, ...attributes }) => {
@@ -207,7 +208,7 @@ const Regions = memo(({ config, updateConfig }) => {
207
208
  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
209
 
209
210
  const EditorPanel = () => {
210
- const { config, updateConfig, transformedData: data, loading, colorPalettes, twoColorPalette, unfilteredData, excludedData, isDashboard, setParentConfig, missingRequiredSections, isDebug, setFilteredData } = useContext(ConfigContext)
211
+ const { config, updateConfig, transformedData: data, loading, colorPalettes, twoColorPalette, unfilteredData, excludedData, isDashboard, setParentConfig, missingRequiredSections, isDebug, setFilteredData, lineOptions, rawData } = useContext(ConfigContext)
211
212
 
212
213
  const { minValue, maxValue, existPositiveValue, isAllLine } = useReduceData(config, unfilteredData)
213
214
 
@@ -216,14 +217,6 @@ const EditorPanel = () => {
216
217
  // argument acts as props
217
218
  const { handleFilterOrder, filterOrderOptions, filterStyleOptions } = useFilters({ config, setConfig: updateConfig, filteredData: data, setFilteredData })
218
219
 
219
- const approvedCurveTypes = {
220
- Linear: 'curveLinear',
221
- Cardinal: 'curveCardinal',
222
- Natural: 'curveNatural',
223
- 'Monotone X': 'curveMonotoneX',
224
- Step: 'curveStep'
225
- }
226
-
227
220
  // when the visualization type changes we
228
221
  // have to update the individual series type & axis details
229
222
  // dataKey is unchanged here.
@@ -295,6 +288,8 @@ const EditorPanel = () => {
295
288
  }
296
289
 
297
290
  const updateField = (section, subsection, fieldName, newValue) => {
291
+ if (isDebug) console.log('#COVE: CHART: EditorPanel: section, subsection, fieldName, newValue', section, subsection, fieldName, newValue) // eslint-disable-line
292
+
298
293
  if (section === 'boxplot' && subsection === 'legend') {
299
294
  updateConfig({
300
295
  ...config,
@@ -322,6 +317,20 @@ const EditorPanel = () => {
322
317
  })
323
318
  return
324
319
  }
320
+
321
+ if (section === 'columns' && subsection !== '' && fieldName !== '') {
322
+ updateConfig({
323
+ ...config,
324
+ [section]: {
325
+ ...config[section],
326
+ [subsection]: {
327
+ ...config[section][subsection],
328
+ [fieldName]: newValue
329
+ }
330
+ }
331
+ })
332
+ return
333
+ }
325
334
  if (null === section && null === subsection) {
326
335
  let updatedConfig = { ...config, [fieldName]: newValue }
327
336
  enforceRestrictions(updatedConfig)
@@ -490,7 +499,6 @@ const EditorPanel = () => {
490
499
 
491
500
  const getColumns = (filter = true) => {
492
501
  let columns = {}
493
-
494
502
  unfilteredData.forEach(row => {
495
503
  Object.keys(row).forEach(columnName => (columns[columnName] = true))
496
504
  })
@@ -598,6 +606,24 @@ const EditorPanel = () => {
598
606
  // eslint-disable-next-line react-hooks/exhaustive-deps
599
607
  }, [config])
600
608
 
609
+ // when the orientation changes, swap x and y axis anchors
610
+ useEffect(() => {
611
+ const prevXAnchors = config.xAxis.anchors.length > 0 ? config.xAxis.anchors : []
612
+ const prevYAnchors = config.yAxis.anchors.length > 0 ? config.yAxis.anchors : []
613
+
614
+ updateConfig({
615
+ ...config,
616
+ xAxis: {
617
+ ...config.xAxis,
618
+ anchors: prevYAnchors
619
+ },
620
+ yAxis: {
621
+ ...config.yAxis,
622
+ anchors: prevXAnchors
623
+ }
624
+ })
625
+ }, [config.orientation])
626
+
601
627
  // Set paired bars to be horizontal, even though that option doesn't display
602
628
  useEffect(() => {
603
629
  if (config.visualizationType === 'Paired Bar') {
@@ -644,6 +670,12 @@ const EditorPanel = () => {
644
670
  )
645
671
  }, [config]) // eslint-disable-line
646
672
 
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
+
647
679
  const visHasLegend = () => {
648
680
  const { visualizationType } = config
649
681
 
@@ -697,6 +729,24 @@ const EditorPanel = () => {
697
729
  }
698
730
  }
699
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
+
700
750
  const visHasBarBorders = () => {
701
751
  const { series, visualizationType } = config
702
752
  if (visualizationType === 'Box Plot') return false
@@ -737,9 +787,7 @@ const EditorPanel = () => {
737
787
  default:
738
788
  message = ''
739
789
  }
740
- setWarningMsg(function (prevMsg) {
741
- return { ...prevMsg, maxMsg: message }
742
- })
790
+ setWarningMsg(prevMsg => ({ ...prevMsg, maxMsg: message }))
743
791
  }
744
792
 
745
793
  const validateMinValue = () => {
@@ -748,27 +796,28 @@ const EditorPanel = () => {
748
796
  let message = ''
749
797
 
750
798
  switch (true) {
799
+ case config.useLogScale && ['Line', 'Combo', 'Bar'].includes(config.visualizationType) && enteredValue < 0:
800
+ message = 'Negative numbers are not supported in logarithmic scale'
801
+ break
751
802
  case (config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && enteredValue && parseFloat(enteredValue) > minVal:
752
- message = 'Value must be less than ' + minValue
803
+ message = 'Value should not exceed ' + minValue
753
804
  break
754
805
  case config.visualizationType === 'Combo' && isAllLine && enteredValue && parseFloat(enteredValue) > minVal:
755
- message = 'Value must be less than ' + minValue
806
+ message = 'Value should not exceed ' + minValue
756
807
  break
757
808
  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'
809
+ message = config.useLogScale ? 'Value must be equal to 0' : 'Value must be less than or equal to 0'
759
810
  break
760
811
  case config.visualizationType === 'Deviation Bar' && parseFloat(enteredValue) >= Math.min(minVal, config.xAxis.target):
761
812
  message = 'Value must be less than ' + Math.min(minVal, config.xAxis.target)
762
813
  break
763
814
  case config.visualizationType !== 'Deviation Bar' && enteredValue && minVal < 0 && parseFloat(enteredValue) > minVal:
764
- message = 'Value must be less than ' + minValue
815
+ message = 'Value should not exceed ' + minValue
765
816
  break
766
817
  default:
767
818
  message = ''
768
819
  }
769
- setWarningMsg(function (prevMsg) {
770
- return { ...prevMsg, minMsg: message }
771
- })
820
+ setWarningMsg(prevMsg => ({ ...prevMsg, minMsg: message }))
772
821
  }
773
822
  useEffect(() => {
774
823
  validateMinValue()
@@ -777,11 +826,12 @@ const EditorPanel = () => {
777
826
 
778
827
  // prettier-ignore
779
828
  const enabledChartTypes = [
780
- // 'Area Chart',
829
+ 'Area Chart',
781
830
  'Bar',
782
831
  'Box Plot',
783
832
  'Combo',
784
833
  'Deviation Bar',
834
+ // 'Forecasting',
785
835
  'Line',
786
836
  'Paired Bar',
787
837
  'Pie',
@@ -799,15 +849,16 @@ const EditorPanel = () => {
799
849
  let datakeys = getColumns(false)
800
850
  if (datakeys.includes('Date')) return 'Date'
801
851
  if (datakeys.includes('Race')) return 'Race'
852
+ if (datakeys.includes('Month')) return 'Month'
802
853
  // add other known Category cols here to extend debug
803
854
  }
804
- return ''
855
+ return config?.xAxis?.dataKey || ''
805
856
  }
806
857
  const setDataColumn = () => {
807
858
  // only for debug mode
808
859
  if (undefined !== isDebug && isDebug && getColumns(false).length > 0) {
809
860
  // then try to set the x axis to appropriate value so we dont have to manually do it
810
- let datacols = getColumns(false).filter(x => x !== 'Date' && x !== 'Race')
861
+ let datacols = getColumns(false).filter(x => x !== setCategoryAxis())
811
862
  if (datacols.length > 0) {
812
863
  return datacols[0]
813
864
  }
@@ -821,7 +872,151 @@ const EditorPanel = () => {
821
872
  if (isDebug) console.log('### COVE DEBUG: Chart: Setting default datacol=', setdatacol) // eslint-disable-line
822
873
  }
823
874
 
824
- const chartsWithOptions = ['Area Chart', 'Combo', 'Line']
875
+ const chartsWithOptions = ['Area Chart', 'Combo', 'Line', 'Bar', 'Forecasting']
876
+
877
+ const columnsOptions = [
878
+ <option value='' key={'Select Option'}>
879
+ - Select Option -
880
+ </option>
881
+ ]
882
+
883
+ if (config.data && config.series) {
884
+ Object.keys(config.data[0]).map(colName => {
885
+ // OMIT ANY COLUMNS THAT ARE IN DATA SERIES!
886
+ const found = config?.series.some(el => el.dataKey === colName)
887
+ if (colName !== config.xAxis.dataKey && !found) {
888
+ // if not the index then add it
889
+ return columnsOptions.push(
890
+ <option value={colName} key={colName}>
891
+ {colName}
892
+ </option>
893
+ )
894
+ }
895
+ })
896
+
897
+ let columnsByKey = {}
898
+ config.data.forEach(datum => {
899
+ Object.keys(datum).forEach(key => {
900
+ columnsByKey[key] = columnsByKey[key] || []
901
+ const value = typeof datum[key] === 'number' ? datum[key].toString() : datum[key]
902
+
903
+ if (columnsByKey[key].indexOf(value) === -1) {
904
+ columnsByKey[key].push(value)
905
+ }
906
+ })
907
+ })
908
+ }
909
+
910
+ // for pie charts
911
+ if (!config.data && data) {
912
+ if (!data[0]) return
913
+ Object.keys(data[0]).map(colName => {
914
+ // OMIT ANY COLUMNS THAT ARE IN DATA SERIES!
915
+ const found = data.some(el => el.dataKey === colName)
916
+ if (colName !== config.xAxis.dataKey && !found) {
917
+ // if not the index then add it
918
+ return columnsOptions.push(
919
+ <option value={colName} key={colName}>
920
+ {colName}
921
+ </option>
922
+ )
923
+ }
924
+ })
925
+
926
+ let columnsByKey = {}
927
+ data.forEach(datum => {
928
+ Object.keys(datum).forEach(key => {
929
+ columnsByKey[key] = columnsByKey[key] || []
930
+ const value = typeof datum[key] === 'number' ? datum[key].toString() : datum[key]
931
+
932
+ if (columnsByKey[key].indexOf(value) === -1) {
933
+ columnsByKey[key].push(value)
934
+ }
935
+ })
936
+ })
937
+ }
938
+
939
+ // prevents adding duplicates
940
+ const additionalColumns = Object.keys(config.columns).filter(value => {
941
+ const defaultCols = [config.xAxis.dataKey] // ['geo', 'navigate', 'primary', 'latitude', 'longitude']
942
+
943
+ if (true === defaultCols.includes(value)) {
944
+ return false
945
+ }
946
+ return true
947
+ })
948
+
949
+ // just adds a new column but not set to any data yet
950
+ const addAdditionalColumn = number => {
951
+ const columnKey = `additionalColumn${number}`
952
+
953
+ updateConfig({
954
+ ...config,
955
+ columns: {
956
+ ...config.columns,
957
+ [columnKey]: {
958
+ label: 'New Column',
959
+ dataTable: false,
960
+ tooltips: false,
961
+ prefix: '',
962
+ suffix: ''
963
+ }
964
+ }
965
+ })
966
+ }
967
+
968
+ const removeAdditionalColumn = columnName => {
969
+ const newColumns = config.columns
970
+
971
+ delete newColumns[columnName]
972
+
973
+ updateConfig({
974
+ ...config,
975
+ columns: newColumns
976
+ })
977
+ }
978
+
979
+ const editColumn = async (addCol, columnName, setval) => {
980
+ // not using special classes like in map editorpanel so removed those cases
981
+ switch (columnName) {
982
+ case 'name':
983
+ updateConfig({
984
+ ...config,
985
+ columns: {
986
+ ...config.columns,
987
+ [addCol]: {
988
+ ...config.columns[addCol],
989
+ [columnName]: setval
990
+ }
991
+ }
992
+ })
993
+ break
994
+ default:
995
+ updateConfig({
996
+ ...config,
997
+ columns: {
998
+ ...config.columns,
999
+ [addCol]: {
1000
+ ...config.columns[addCol],
1001
+ [columnName]: setval
1002
+ }
1003
+ }
1004
+ })
1005
+ break
1006
+ }
1007
+ }
1008
+
1009
+ // prettier-ignore
1010
+ const {
1011
+ highlightedBarValues,
1012
+ highlightedSeriesValues,
1013
+ handleUpdateHighlightedBar,
1014
+ handleAddNewHighlightedBar,
1015
+ handleRemoveHighlightedBar,
1016
+ handleUpdateHighlightedBarColor,
1017
+ handleHighlightedBarLegendLabel,
1018
+ handleUpdateHighlightedBorderWidth
1019
+ } = useHighlightedBars(config, updateConfig)
825
1020
 
826
1021
  return (
827
1022
  <ErrorBoundary component='EditorPanel'>
@@ -833,94 +1028,274 @@ const EditorPanel = () => {
833
1028
  Configure Chart
834
1029
  </div>
835
1030
  <section className='form-container'>
836
- <form>
837
- <Accordion allowZeroExpanded={true}>
1031
+ <Accordion allowZeroExpanded={true}>
1032
+ <AccordionItem>
1033
+ {' '}
1034
+ {/* General */}
1035
+ <AccordionItemHeading>
1036
+ <AccordionItemButton>General</AccordionItemButton>
1037
+ </AccordionItemHeading>
1038
+ <AccordionItemPanel>
1039
+ <Select value={config.visualizationType} fieldName='visualizationType' label='Chart Type' updateField={updateField} options={enabledChartTypes} />
1040
+ {(config.visualizationType === 'Bar' || config.visualizationType === 'Combo') && <Select value={config.visualizationSubType || 'Regular'} fieldName='visualizationSubType' label='Chart Subtype' updateField={updateField} options={['regular', 'stacked']} />}
1041
+ {config.visualizationType === 'Bar' && <Select value={config.orientation || 'vertical'} fieldName='orientation' label='Orientation' updateField={updateField} options={['vertical', 'horizontal']} />}
1042
+ {config.visualizationType === 'Deviation Bar' && <Select label='Orientation' options={['horizontal']} />}
1043
+ {(config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && <Select value={config.isLollipopChart ? 'lollipop' : config.barStyle || 'flat'} fieldName='barStyle' label='bar style' updateField={updateField} options={showBarStyleOptions()} />}
1044
+ {(config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.barStyle === 'rounded' && <Select value={config.tipRounding || 'top'} fieldName='tipRounding' label='tip rounding' updateField={updateField} options={['top', 'full']} />}
1045
+ {(config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.barStyle === 'rounded' && (
1046
+ <Select value={config.roundingStyle || 'standard'} fieldName='roundingStyle' label='rounding style' updateField={updateField} options={['standard', 'shallow', 'finger']} />
1047
+ )}
1048
+ {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') ? (
1050
+ <CheckBox value={config.yAxis.displayNumbersOnBar} section='yAxis' fieldName='displayNumbersOnBar' label={config.isLollipopChart ? 'Display Numbers after Bar' : 'Display Numbers on Bar'} updateField={updateField} />
1051
+ ) : (
1052
+ visHasLabelOnData() && <CheckBox value={config.labels} fieldName='labels' label='Display label on data' updateField={updateField} />
1053
+ )}
1054
+ {config.visualizationType === 'Pie' && <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />}
1055
+
1056
+ <TextField
1057
+ value={config.title || 'Chart Title'}
1058
+ fieldName='title'
1059
+ id='title'
1060
+ label='Title'
1061
+ placeholder='Chart Title'
1062
+ //defaultValue='Chart Title'
1063
+ updateField={updateField}
1064
+ //onChange={handleTitleChange}
1065
+ tooltip={
1066
+ <Tooltip style={{ textTransform: 'none' }}>
1067
+ <Tooltip.Target>
1068
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1069
+ </Tooltip.Target>
1070
+ <Tooltip.Content>
1071
+ <p>Title is required to set the name of the download file but can be hidden using the option below.</p>
1072
+ </Tooltip.Content>
1073
+ </Tooltip>
1074
+ }
1075
+ />
1076
+ <CheckBox value={config.showTitle} fieldName='showTitle' label='Show Title' updateField={updateField} />
1077
+ <TextField
1078
+ value={config.superTitle}
1079
+ updateField={updateField}
1080
+ fieldName='superTitle'
1081
+ label='Super Title'
1082
+ placeholder='Super Title'
1083
+ tooltip={
1084
+ <Tooltip style={{ textTransform: 'none' }}>
1085
+ <Tooltip.Target>
1086
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1087
+ </Tooltip.Target>
1088
+ <Tooltip.Content>
1089
+ <p>Super Title</p>
1090
+ </Tooltip.Content>
1091
+ </Tooltip>
1092
+ }
1093
+ />
1094
+
1095
+ <TextField
1096
+ type='textarea'
1097
+ value={config.introText}
1098
+ updateField={updateField}
1099
+ fieldName='introText'
1100
+ label='Intro Text'
1101
+ tooltip={
1102
+ <Tooltip style={{ textTransform: 'none' }}>
1103
+ <Tooltip.Target>
1104
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1105
+ </Tooltip.Target>
1106
+ <Tooltip.Content>
1107
+ <p>Intro Text</p>
1108
+ </Tooltip.Content>
1109
+ </Tooltip>
1110
+ }
1111
+ />
1112
+
1113
+ <TextField
1114
+ type='textarea'
1115
+ value={config.description}
1116
+ fieldName='description'
1117
+ label='Subtext'
1118
+ updateField={updateField}
1119
+ tooltip={
1120
+ <Tooltip style={{ textTransform: 'none' }}>
1121
+ <Tooltip.Target>
1122
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1123
+ </Tooltip.Target>
1124
+ <Tooltip.Content>
1125
+ <p>Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
1126
+ </Tooltip.Content>
1127
+ </Tooltip>
1128
+ }
1129
+ />
1130
+
1131
+ <TextField
1132
+ type='textarea'
1133
+ value={config.footnotes}
1134
+ updateField={updateField}
1135
+ fieldName='footnotes'
1136
+ label='Footnotes'
1137
+ tooltip={
1138
+ <Tooltip style={{ textTransform: 'none' }}>
1139
+ <Tooltip.Target>
1140
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1141
+ </Tooltip.Target>
1142
+ <Tooltip.Content>
1143
+ <p>Footnotes</p>
1144
+ </Tooltip.Content>
1145
+ </Tooltip>
1146
+ }
1147
+ />
1148
+
1149
+ {config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
1150
+ </AccordionItemPanel>
1151
+ </AccordionItem>
1152
+ {config.visualizationType !== 'Pie' && (
838
1153
  <AccordionItem>
839
- {' '}
840
- {/* General */}
841
1154
  <AccordionItemHeading>
842
- <AccordionItemButton>General</AccordionItemButton>
1155
+ <AccordionItemButton>Data Series {(!config.series || config.series.length === 0 || (config.visualizationType === 'Paired Bar' && config.series.length < 2)) && <WarningImage width='25' className='warning-icon' />}</AccordionItemButton>
843
1156
  </AccordionItemHeading>
844
1157
  <AccordionItemPanel>
845
- <Select value={config.visualizationType} fieldName='visualizationType' label='Chart Type' updateField={updateField} options={enabledChartTypes} />
846
- {(config.visualizationType === 'Bar' || config.visualizationType === 'Combo') && <Select value={config.visualizationSubType || 'Regular'} fieldName='visualizationSubType' label='Chart Subtype' updateField={updateField} options={['regular', 'stacked']} />}
847
- {config.visualizationType === 'Bar' && <Select value={config.orientation || 'vertical'} fieldName='orientation' label='Orientation' updateField={updateField} options={['vertical', 'horizontal']} />}
848
- {config.visualizationType === 'Deviation Bar' && <Select label='Orientation' options={['horizontal']} />}
849
- {(config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && <Select value={config.isLollipopChart ? 'lollipop' : config.barStyle || 'flat'} fieldName='barStyle' label='bar style' updateField={updateField} options={showBarStyleOptions()} />}
850
- {(config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.barStyle === 'rounded' && <Select value={config.tipRounding || 'top'} fieldName='tipRounding' label='tip rounding' updateField={updateField} options={['top', 'full']} />}
851
- {(config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.barStyle === 'rounded' && (
852
- <Select value={config.roundingStyle || 'standard'} fieldName='roundingStyle' label='rounding style' updateField={updateField} options={['standard', 'shallow', 'finger']} />
853
- )}
854
- {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']} />}
855
- {config.orientation === 'horizontal' && (config.yAxis.labelPlacement === 'Below Bar' || config.yAxis.labelPlacement === 'On Date/Category Axis' || config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') ? (
856
- <CheckBox value={config.yAxis.displayNumbersOnBar} section='yAxis' fieldName='displayNumbersOnBar' label={config.isLollipopChart ? 'Display Numbers after Bar' : 'Display Numbers on Bar'} updateField={updateField} />
857
- ) : (
858
- visHasLabelOnData() && <CheckBox value={config.labels} fieldName='labels' label='Display label on data' updateField={updateField} />
1158
+ {(!config.series || config.series.length === 0) && config.visualizationType !== 'Paired Bar' && <p className='warning'>At least one series is required</p>}
1159
+ {(!config.series || config.series.length === 0 || config.series.length < 2) && config.visualizationType === 'Paired Bar' && <p className='warning'>Select two data series for paired bar chart (e.g., Male and Female).</p>}
1160
+ <>
1161
+ <Select
1162
+ fieldName='visualizationType'
1163
+ label='Add Data Series'
1164
+ initial='Select'
1165
+ onChange={e => {
1166
+ if (e.target.value !== '' && e.target.value !== 'Select') {
1167
+ addNewSeries(e.target.value)
1168
+ }
1169
+ e.target.value = ''
1170
+ }}
1171
+ options={getColumns()}
1172
+ />
1173
+ {config.series && config.series.length !== 0 && (
1174
+ <Series.Wrapper getColumns={getColumns}>
1175
+ <fieldset>
1176
+ <legend className='edit-label float-left'>Displaying</legend>
1177
+ <Tooltip style={{ textTransform: 'none' }}>
1178
+ <Tooltip.Target>
1179
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1180
+ </Tooltip.Target>
1181
+ <Tooltip.Content>
1182
+ <p>A data series is a set of related data points plotted in a chart and typically represented in the chart legend.</p>
1183
+ </Tooltip.Content>
1184
+ </Tooltip>
1185
+ </fieldset>
1186
+
1187
+ <DragDropContext onDragEnd={({ source, destination }) => handleSeriesChange(source.index, destination.index)}>
1188
+ <Droppable droppableId='filter_order'>
1189
+ {/* prettier-ignore */}
1190
+ {provided => {
1191
+ return (
1192
+ <ul {...provided.droppableProps} className='series-list' ref={provided.innerRef}>
1193
+ <Series.List series={config.series} getItemStyle={getItemStyle} sortableItemStyles={sortableItemStyles} chartsWithOptions={chartsWithOptions} />
1194
+ {provided.placeholder}
1195
+ </ul>
1196
+ )
1197
+ }}
1198
+ </Droppable>
1199
+ </DragDropContext>
1200
+ </Series.Wrapper>
1201
+ )}
1202
+ </>
1203
+
1204
+ {config.series && config.series.length <= 1 && config.visualizationType === 'Bar' && (
1205
+ <>
1206
+ <span className='divider-heading'>Confidence Keys</span>
1207
+ <Select value={config.confidenceKeys.upper || ''} section='confidenceKeys' fieldName='upper' label='Upper' updateField={updateField} initial='Select' options={getColumns()} />
1208
+ <Select value={config.confidenceKeys.lower || ''} section='confidenceKeys' fieldName='lower' label='Lower' updateField={updateField} initial='Select' options={getColumns()} />
1209
+ </>
859
1210
  )}
860
- {config.visualizationType === 'Pie' && <Select fieldName='pieType' label='Pie Chart Type' updateField={updateField} options={['Regular', 'Donut']} />}
861
1211
 
1212
+ {config.series && config.series.length === 1 && <Select fieldName='visualizationType' label='Rank by Value' initial='Select' onChange={e => sortSeries(e.target.value)} options={['asc', 'desc']} />}
1213
+ </AccordionItemPanel>
1214
+ </AccordionItem>
1215
+ )}
1216
+ {config.visualizationType === 'Box Plot' && (
1217
+ <AccordionItem>
1218
+ <AccordionItemHeading>
1219
+ <AccordionItemButton>Measures</AccordionItemButton>
1220
+ </AccordionItemHeading>
1221
+ <AccordionItemPanel>
1222
+ <h4 style={{ fontSize: '18px' }}>Labels for 5-Number Summary</h4>
1223
+
1224
+ {/* prettier-ignore */}
1225
+ {/* max */}
862
1226
  <TextField
863
- value={config.title || 'Chart Title'}
864
- fieldName='title'
865
- id='title'
866
- label='Title'
867
- placeholder='Chart Title'
868
- //defaultValue='Chart Title'
1227
+ type='text'
1228
+ value={config.boxplot.labels.maximum}
1229
+ fieldName='maximum'
1230
+ section='boxplot'
1231
+ subsection='labels'
1232
+ label='Maximum'
869
1233
  updateField={updateField}
870
- //onChange={handleTitleChange}
871
1234
  tooltip={
872
1235
  <Tooltip style={{ textTransform: 'none' }}>
873
1236
  <Tooltip.Target>
874
1237
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
875
1238
  </Tooltip.Target>
876
1239
  <Tooltip.Content>
877
- <p>Title is required to set the name of the download file but can be hidden using the option below.</p>
1240
+ <p>Highest value, excluding outliers</p>
878
1241
  </Tooltip.Content>
879
1242
  </Tooltip>
880
1243
  }
881
1244
  />
882
- <CheckBox value={config.showTitle} fieldName='showTitle' label='Show Title' updateField={updateField} />
1245
+
1246
+ {/* prettier-ignore */}
1247
+ {/* Q3 */}
883
1248
  <TextField
884
- value={config.superTitle}
1249
+ type='text'
1250
+ value={config.boxplot.labels.q3}
1251
+ fieldName='q3'
1252
+ section='boxplot'
1253
+ subsection='labels'
1254
+ label='Upper Quartile'
885
1255
  updateField={updateField}
886
- fieldName='superTitle'
887
- label='Super Title'
888
- placeholder='Super Title'
889
1256
  tooltip={
890
1257
  <Tooltip style={{ textTransform: 'none' }}>
891
1258
  <Tooltip.Target>
892
1259
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
893
1260
  </Tooltip.Target>
894
1261
  <Tooltip.Content>
895
- <p>Super Title</p>
1262
+ <p>Represented by top line of box. 25% of data are higher.</p>
896
1263
  </Tooltip.Content>
897
1264
  </Tooltip>
898
1265
  }
899
1266
  />
900
1267
 
1268
+ {/* prettier-ignore */}
1269
+ {/* median */}
901
1270
  <TextField
902
- type='textarea'
903
- value={config.introText}
1271
+ type='text'
1272
+ value={config.boxplot.labels.median}
1273
+ fieldName='median'
1274
+ section='boxplot'
1275
+ subsection='labels'
1276
+ label='Median'
904
1277
  updateField={updateField}
905
- fieldName='introText'
906
- label='Intro Text'
907
1278
  tooltip={
908
1279
  <Tooltip style={{ textTransform: 'none' }}>
909
1280
  <Tooltip.Target>
910
1281
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
911
1282
  </Tooltip.Target>
912
1283
  <Tooltip.Content>
913
- <p>Intro Text</p>
1284
+ <p>Middle data point. Half of data are higher value.</p>
914
1285
  </Tooltip.Content>
915
1286
  </Tooltip>
916
1287
  }
917
1288
  />
918
1289
 
1290
+ {/* prettier-ignore */}
1291
+ {/* q1 */}
919
1292
  <TextField
920
- type='textarea'
921
- value={config.description}
922
- fieldName='description'
923
- label='Subtext'
1293
+ type='text'
1294
+ value={config.boxplot.labels.q1}
1295
+ fieldName='q1'
1296
+ section='boxplot'
1297
+ subsection='labels'
1298
+ label='Lower Quartile'
924
1299
  updateField={updateField}
925
1300
  tooltip={
926
1301
  <Tooltip style={{ textTransform: 'none' }}>
@@ -928,406 +1303,522 @@ const EditorPanel = () => {
928
1303
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
929
1304
  </Tooltip.Target>
930
1305
  <Tooltip.Content>
931
- <p>Enter supporting text to display below the data visualization, if applicable. The following HTML tags are supported: strong, em, sup, and sub.</p>
1306
+ <p>Represented by bottom line of box. 25% of data are lower.</p>
932
1307
  </Tooltip.Content>
933
1308
  </Tooltip>
934
1309
  }
935
1310
  />
936
1311
 
1312
+ {/* prettier-ignore */}
1313
+ {/* minimum */}
937
1314
  <TextField
938
- type='textarea'
939
- value={config.footnotes}
1315
+ type='text'
1316
+ value={config.boxplot.labels.minimum}
1317
+ fieldName='minimum'
1318
+ section='boxplot'
1319
+ subsection='labels'
1320
+ label='Minimum'
1321
+ updateField={updateField}
1322
+ tooltip={
1323
+ <Tooltip style={{ textTransform: 'none' }}>
1324
+ <Tooltip.Target>
1325
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1326
+ </Tooltip.Target>
1327
+ <Tooltip.Content>
1328
+ <p>Lowest value, excluding outliers</p>
1329
+ </Tooltip.Content>
1330
+ </Tooltip>
1331
+ }
1332
+ />
1333
+ <br />
1334
+ <h4 style={{ fontSize: '18px' }}>Labels for Additional Measures</h4>
1335
+
1336
+ {/* iqr */}
1337
+ <TextField type='text' value={config.boxplot.labels.iqr} fieldName='iqr' section='boxplot' subsection='labels' label='Interquartile Range' updateField={updateField} />
1338
+
1339
+ {/* count */}
1340
+ <TextField type='text' value={config.boxplot.labels.total} fieldName='total' section='boxplot' subsection='labels' label='Total' updateField={updateField} />
1341
+
1342
+ {/* mean */}
1343
+ <TextField type='text' value={config.boxplot.labels.mean} fieldName='mean' section='boxplot' subsection='labels' label='Mean' updateField={updateField} />
1344
+ {/* outliers */}
1345
+ <TextField type='text' value={config.boxplot.labels.outliers} fieldName='outliers' section='boxplot' subsection='labels' label='Outliers' updateField={updateField} />
1346
+ {/* values */}
1347
+ <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}
940
1357
  updateField={updateField}
941
- fieldName='footnotes'
942
- label='Footnotes'
943
1358
  tooltip={
944
1359
  <Tooltip style={{ textTransform: 'none' }}>
945
1360
  <Tooltip.Target>
946
1361
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
947
1362
  </Tooltip.Target>
948
1363
  <Tooltip.Content>
949
- <p>Footnotes</p>
1364
+ <p>Represented by bottom line of box. 25% of data are lower.</p>
950
1365
  </Tooltip.Content>
951
1366
  </Tooltip>
952
1367
  }
953
1368
  />
954
1369
 
955
- {config.orientation === 'vertical' && <TextField type='number' value={config.heights.vertical} section='heights' fieldName='vertical' label='Chart Height' updateField={updateField} />}
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
+ />
956
1389
  </AccordionItemPanel>
957
1390
  </AccordionItem>
958
-
959
- {config.visualizationType !== 'Pie' && (
960
- <AccordionItem>
961
- <AccordionItemHeading>
962
- <AccordionItemButton>Data Series {(!config.series || config.series.length === 0 || (config.visualizationType === 'Paired Bar' && config.series.length < 2)) && <WarningImage width='25' className='warning-icon' />}</AccordionItemButton>
963
- </AccordionItemHeading>
964
- <AccordionItemPanel>
965
- {(!config.series || config.series.length === 0) && config.visualizationType !== 'Paired Bar' && <p className='warning'>At least one series is required</p>}
966
- {(!config.series || config.series.length === 0 || config.series.length < 2) && config.visualizationType === 'Paired Bar' && <p className='warning'>Select two data series for paired bar chart (e.g., Male and Female).</p>}
967
- <Select
968
- fieldName='visualizationType'
969
- label='Add Data Series'
970
- initial='Select'
971
- onChange={e => {
972
- if (e.target.value !== '' && e.target.value !== 'Select') {
973
- addNewSeries(e.target.value)
974
- }
975
- e.target.value = ''
976
- }}
977
- options={getColumns()}
978
- />
979
- {config.series && config.series.length !== 0 && (
980
- <>
981
- <fieldset>
982
- <legend className='edit-label float-left'>Displaying</legend>
983
- <Tooltip style={{ textTransform: 'none' }}>
984
- <Tooltip.Target>
985
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
986
- </Tooltip.Target>
987
- <Tooltip.Content>
988
- <p>A data series is a set of related data points plotted in a chart and typically represented in the chart legend.</p>
989
- </Tooltip.Content>
990
- </Tooltip>
991
- </fieldset>
992
-
993
- <DragDropContext onDragEnd={({ source, destination }) => handleSeriesChange(source.index, destination.index)}>
994
- <Droppable droppableId='filter_order'>
995
- {provided => (
996
- <ul {...provided.droppableProps} className='series-list' ref={provided.innerRef}>
997
- {config.series.map((series, i) => {
998
- if (config.visualizationType === 'Combo' || 'Area Chart') {
999
- let changeType = (i, value) => {
1000
- let series = [...config.series]
1001
- series[i].type = value
1002
-
1003
- series[i].axis = 'Left'
1004
-
1005
- updateConfig({ ...config, series })
1006
- }
1007
-
1008
- let changeLineType = (i, value) => {
1009
- let series = [...config.series]
1010
- series[i].lineType = value
1011
- updateConfig({ ...config, series })
1012
- }
1013
-
1014
- let typeDropdown = (
1015
- <>
1016
- <label htmlFor='type-dropdown'>Series Type</label>
1017
- <select
1018
- name='type-dropdown'
1019
- value={series.type}
1020
- onChange={event => {
1021
- changeType(i, event.target.value)
1022
- }}
1023
- >
1024
- <option value='' default key='default'>
1025
- Select
1026
- </option>
1027
- {config.visualizationType === 'Combo' && <option value='Bar'>Bar</option>}
1028
- <option value='Line' key='Line'>
1029
- Solid Line
1030
- </option>
1031
- <option value='dashed-sm' key='dashed-sm'>
1032
- Small Dashed
1033
- </option>
1034
- <option value='dashed-md' key='dashed-md'>
1035
- Medium Dashed
1036
- </option>
1037
- <option value='dashed-lg' key='dashed-lg'>
1038
- Large Dashed
1039
- </option>
1040
- <option value='Area Chart' key='Area Chart'>
1041
- Area
1042
- </option>
1043
- </select>
1044
- </>
1045
- )
1046
-
1047
- // used for assigning axis
1048
- let changeAxis = (i, value) => {
1049
- let series = [...config.series]
1050
- series[i].axis = value
1051
- updateConfig({ ...config, series })
1052
- }
1053
-
1054
- // assign an axis dropdown
1055
- let axisDropdown = (
1056
- <>
1057
- <label htmlFor='assign-axis'>Assign an axis</label>
1058
- <select
1059
- name='assign-axis'
1060
- value={series.axis}
1061
- onChange={event => {
1062
- changeAxis(i, event.target.value)
1063
- }}
1064
- >
1065
- <option value='Left' default key='left'>
1066
- left
1067
- </option>
1068
- <option value='Right' key='right'>
1069
- right
1070
- </option>
1071
- </select>
1072
- </>
1073
- )
1074
-
1075
- // line type dropdown
1076
- const lineType = (
1077
- <>
1078
- <label htmlFor='line-type'>Line Type</label>
1079
- <select
1080
- name='line-type'
1081
- value={series.lineStyle}
1082
- onChange={event => {
1083
- changeLineType(i, event.target.value)
1084
- }}
1085
- key='lineTypeSelection'
1086
- >
1087
- <option value='' default>
1088
- Select
1089
- </option>
1090
-
1091
- {Object.keys(approvedCurveTypes).map(curveName => {
1092
- return (
1093
- <option key={`curve-option-${approvedCurveTypes[curveName]}`} value={approvedCurveTypes[curveName]}>
1094
- {curveName}
1095
- </option>
1096
- )
1097
- })}
1098
- </select>
1099
- </>
1100
- )
1101
-
1102
- return (
1103
- <Draggable key={series.dataKey} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
1104
- {(provided, snapshot) => (
1105
- <>
1106
- <div key={i} className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
1107
- <div className={`series-list__name ${series.dataKey.length > 15 ? ' series-list__name--truncate' : ''}`} data-title={series.dataKey}></div>
1108
- <Accordion allowZeroExpanded>
1109
- <AccordionItem className='series-item series-item--chart'>
1110
- <AccordionItemHeading className='series-item__title'>
1111
- <AccordionItemButton className={chartsWithOptions.includes(config.visualizationType) ? 'accordion__button' : 'accordion__button hide-arrow'}>
1112
- <Icon display='move' size={15} style={{ cursor: 'default' }} />
1113
- {series.dataKey}
1114
- {config.series && config.series.length > 1 && (
1115
- <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
1116
- Remove
1117
- </button>
1118
- )}
1119
- </AccordionItemButton>
1120
- </AccordionItemHeading>
1121
- {chartsWithOptions.includes(config.visualizationType) && (
1122
- <AccordionItemPanel>
1123
- <div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>
1124
- {config.visualizationType === 'Combo' && (
1125
- <>
1126
- <span className='series-list__dropdown series-item__dropdown'>{typeDropdown}</span>
1127
- {hasRightAxis && config.series && (series.type === 'Line' || series.type === 'dashed-sm' || series.type === 'dashed-md' || series.type === 'dashed-lg') && <span className='series-item__dropdown series-list__dropdown'>{axisDropdown}</span>}
1128
- </>
1129
- )}
1130
- {['Line', 'dashed-sm', 'dashed-md', 'dashed-lg', 'Area Chart'].some(item => item.includes(series.type)) && <span className='series-item__dropdown series-list__dropdown series-list__dropdown--lineType'>{lineType}</span>}
1131
- </div>
1132
- </AccordionItemPanel>
1133
- )}
1134
- </AccordionItem>
1135
- </Accordion>
1136
- </div>
1137
- </>
1138
- )}
1139
- </Draggable>
1140
- )
1141
- }
1142
-
1143
- return (
1144
- <Draggable key={`series.dataKey--${i}`} draggableId={`draggableFilter-${series.dataKey}`} index={i}>
1145
- {(provided, snapshot) => (
1146
- <li
1147
- key={series.dataKey}
1148
- className={snapshot.isDragging ? 'currently-dragging' : ''}
1149
- style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)}
1150
- ref={provided.innerRef}
1151
- {...provided.draggableProps}
1152
- {...provided.dragHandleProps}
1153
- >
1154
- {/*<div className={snapshot.isDragging ? 'currently-dragging' : ''} style={getItemStyle(snapshot.isDragging, provided.draggableProps.style, sortableItemStyles)} ref={provided.innerRef} {...provided.draggableProps} {...provided.dragHandleProps}>*/}
1155
- <div className='series-list__name' data-title={series.dataKey}>
1156
- <div className='series-list__name--text'>{series.dataKey}</div>
1157
- </div>
1158
- {config.series && config.series.length > 1 && (
1159
- <button className='series-list__remove' onClick={() => removeSeries(series.dataKey)}>
1160
- &#215;
1161
- </button>
1162
- )}
1163
- {/*</div>*/}
1164
- </li>
1165
- )}
1166
- </Draggable>
1167
- )
1168
- })}
1169
- {provided.placeholder}
1170
- </ul>
1171
- )}
1172
- </Droppable>
1173
- </DragDropContext>
1174
- </>
1175
- )}
1176
-
1177
- {config.series && config.series.length <= 1 && config.visualizationType === 'Bar' && (
1178
- <>
1179
- <span className='divider-heading'>Confidence Keys</span>
1180
- <Select value={config.confidenceKeys.upper || ''} section='confidenceKeys' fieldName='upper' label='Upper' updateField={updateField} initial='Select' options={getColumns()} />
1181
- <Select value={config.confidenceKeys.lower || ''} section='confidenceKeys' fieldName='lower' label='Lower' updateField={updateField} initial='Select' options={getColumns()} />
1182
- </>
1183
- )}
1184
-
1185
- {config.series && config.series.length === 1 && <Select fieldName='visualizationType' label='Rank by Value' initial='Select' onChange={e => sortSeries(e.target.value)} options={['asc', 'desc']} />}
1186
- </AccordionItemPanel>
1187
- </AccordionItem>
1188
- )}
1189
-
1190
- {config.visualizationType === 'Box Plot' && (
1191
- <AccordionItem>
1192
- <AccordionItemHeading>
1193
- <AccordionItemButton>Measures</AccordionItemButton>
1194
- </AccordionItemHeading>
1195
- <AccordionItemPanel>
1196
- <h4 style={{ fontSize: '18px' }}>Labels for 5-Number Summary</h4>
1197
-
1198
- {/* prettier-ignore */}
1199
- {/* max */}
1200
- <TextField
1201
- type='text'
1202
- value={config.boxplot.labels.maximum}
1203
- fieldName='maximum'
1204
- section='boxplot'
1205
- subsection='labels'
1206
- label='Maximum'
1207
- updateField={updateField}
1208
- tooltip={
1209
- <Tooltip style={{ textTransform: 'none' }}>
1210
- <Tooltip.Target>
1211
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1212
- </Tooltip.Target>
1213
- <Tooltip.Content>
1214
- <p>Highest value, excluding outliers</p>
1215
- </Tooltip.Content>
1216
- </Tooltip>
1217
- }
1218
- />
1219
-
1220
- {/* prettier-ignore */}
1221
- {/* Q3 */}
1222
- <TextField
1223
- type='text'
1224
- value={config.boxplot.labels.q3}
1225
- fieldName='q3'
1226
- section='boxplot'
1227
- subsection='labels'
1228
- label='Upper Quartile'
1229
- updateField={updateField}
1230
- tooltip={
1231
- <Tooltip style={{ textTransform: 'none' }}>
1232
- <Tooltip.Target>
1233
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1234
- </Tooltip.Target>
1235
- <Tooltip.Content>
1236
- <p>Represented by top line of box. 25% of data are higher.</p>
1237
- </Tooltip.Content>
1238
- </Tooltip>
1239
- }
1240
- />
1241
-
1242
- {/* prettier-ignore */}
1243
- {/* median */}
1391
+ )}
1392
+ <AccordionItem>
1393
+ <AccordionItemHeading>
1394
+ <AccordionItemButton>
1395
+ {config.visualizationType !== 'Pie' ? (config.orientation !== 'horizontal' ? 'Left Value Axis' : 'Value Axis') : 'Data Format'}
1396
+ {config.visualizationType === 'Pie' && !config.yAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1397
+ </AccordionItemButton>
1398
+ </AccordionItemHeading>
1399
+ <AccordionItemPanel>
1400
+ {config.visualizationType === 'Pie' && (
1401
+ <Select
1402
+ value={config.yAxis.dataKey || ''}
1403
+ section='yAxis'
1404
+ fieldName='dataKey'
1405
+ label='Data Column'
1406
+ initial='Select'
1407
+ required={true}
1408
+ updateField={updateField}
1409
+ options={getColumns(false)}
1410
+ tooltip={
1411
+ <Tooltip style={{ textTransform: 'none' }}>
1412
+ <Tooltip.Target>
1413
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1414
+ </Tooltip.Target>
1415
+ <Tooltip.Content>
1416
+ <p>Select the source data to be visually represented.</p>
1417
+ </Tooltip.Content>
1418
+ </Tooltip>
1419
+ }
1420
+ />
1421
+ )}
1422
+ {config.visualizationType !== 'Pie' && (
1423
+ <>
1424
+ <TextField value={config.yAxis.label} section='yAxis' fieldName='label' label='Label' updateField={updateField} />
1425
+ {config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && config.visualizationType !== 'Box Plot' && <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />}
1426
+ <TextField value={config.yAxis.numTicks} placeholder='Auto' type='number' section='yAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1427
+ {config.visualizationType === 'Paired Bar' && <TextField value={config.yAxis.tickRotation || 0} type='number' min='0' section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1244
1428
  <TextField
1245
- type='text'
1246
- value={config.boxplot.labels.median}
1247
- fieldName='median'
1248
- section='boxplot'
1249
- subsection='labels'
1250
- label='Median'
1429
+ value={config.yAxis.size}
1430
+ type='number'
1431
+ section='yAxis'
1432
+ fieldName='size'
1433
+ label={config.orientation === 'horizontal' ? 'Size (Height)' : 'Size (Width)'}
1434
+ className='number-narrow'
1251
1435
  updateField={updateField}
1252
1436
  tooltip={
1253
1437
  <Tooltip style={{ textTransform: 'none' }}>
1254
1438
  <Tooltip.Target>
1255
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1439
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1256
1440
  </Tooltip.Target>
1257
1441
  <Tooltip.Content>
1258
- <p>Middle data point. Half of data are higher value.</p>
1259
- </Tooltip.Content>
1260
- </Tooltip>
1261
- }
1262
- />
1263
-
1264
- {/* prettier-ignore */}
1265
- {/* q1 */}
1266
- <TextField
1267
- type='text'
1268
- value={config.boxplot.labels.q1}
1269
- fieldName='q1'
1270
- section='boxplot'
1271
- subsection='labels'
1272
- label='Lower Quartile'
1273
- updateField={updateField}
1274
- tooltip={
1275
- <Tooltip style={{ textTransform: 'none' }}>
1276
- <Tooltip.Target>
1277
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1278
- </Tooltip.Target>
1279
- <Tooltip.Content>
1280
- <p>Represented by bottom line of box. 25% of data are lower.</p>
1442
+ <p>{`Increase the size if elements in the ${config.orientation} axis are being crowded or hidden behind other elements. Decrease if less space is required for the value axis.`}</p>
1281
1443
  </Tooltip.Content>
1282
1444
  </Tooltip>
1283
1445
  }
1284
1446
  />
1447
+ {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
1448
+ {/* <TextField value={config.yAxis.axisPadding} type='number' max={10} min={0} section='yAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
1449
+ {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} />}
1451
+ <CheckBox value={config.yAxis.enablePadding} section='yAxis' fieldName='enablePadding' label='Add Padding to Value Axis Scale' updateField={updateField} />
1452
+ {config.visualizationSubType === 'regular' && <CheckBox value={config.useLogScale} fieldName='useLogScale' label='use logarithmic scale' updateField={updateField} />}
1453
+ </>
1454
+ )}
1455
+ <span className='divider-heading'>Number Formatting</span>
1456
+ <CheckBox value={config.dataFormat.commas} section='dataFormat' fieldName='commas' label='Add commas' updateField={updateField} />
1457
+ <CheckBox
1458
+ value={config.dataFormat.abbreviated}
1459
+ section='dataFormat'
1460
+ fieldName='abbreviated'
1461
+ label='Abbreviate Axis Values'
1462
+ updateField={updateField}
1463
+ tooltip={
1464
+ <Tooltip style={{ textTransform: 'none' }}>
1465
+ <Tooltip.Target>
1466
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1467
+ </Tooltip.Target>
1468
+ <Tooltip.Content>
1469
+ <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
1470
+ </Tooltip.Content>
1471
+ </Tooltip>
1472
+ }
1473
+ />
1474
+ <TextField value={config.dataFormat.roundTo ? config.dataFormat.roundTo : 0} type='number' section='dataFormat' fieldName='roundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1475
+ <div className='two-col-inputs'>
1476
+ <TextField
1477
+ value={config.dataFormat.prefix}
1478
+ section='dataFormat'
1479
+ fieldName='prefix'
1480
+ label='Prefix'
1481
+ updateField={updateField}
1482
+ tooltip={
1483
+ <Tooltip style={{ textTransform: 'none' }}>
1484
+ <Tooltip.Target>
1485
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1486
+ </Tooltip.Target>
1487
+ <Tooltip.Content>
1488
+ {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1489
+ {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
1490
+ </Tooltip.Content>
1491
+ </Tooltip>
1492
+ }
1493
+ />
1494
+ <TextField
1495
+ value={config.dataFormat.suffix}
1496
+ section='dataFormat'
1497
+ fieldName='suffix'
1498
+ label='Suffix'
1499
+ updateField={updateField}
1500
+ tooltip={
1501
+ <Tooltip style={{ textTransform: 'none' }}>
1502
+ <Tooltip.Target>
1503
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1504
+ </Tooltip.Target>
1505
+ <Tooltip.Content>
1506
+ {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1507
+ {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1508
+ </Tooltip.Content>
1509
+ </Tooltip>
1510
+ }
1511
+ />
1512
+ </div>
1513
+
1514
+ {config.orientation === 'horizontal' ? ( // horizontal - x is vertical y is horizontal
1515
+ <>
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} />
1519
+ <TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='max value' type='number' placeholder='Auto' updateField={updateField} />
1520
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1521
+ <TextField value={config.xAxis.min} section='xAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />
1522
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1523
+ {config.visualizationType === 'Deviation Bar' && (
1524
+ <>
1525
+ <TextField value={config.xAxis.target} section='xAxis' fieldName='target' type='number' label='Deviation point' placeholder='Auto' updateField={updateField} />
1526
+ <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} />
1528
+ </>
1529
+ )}
1530
+ </>
1531
+ ) : (
1532
+ config.visualizationType !== 'Pie' && (
1533
+ <>
1534
+ <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1535
+ <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1536
+ <CheckBox value={config.yAxis.hideTicks} section='yAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1285
1537
 
1286
- {/* prettier-ignore */}
1287
- {/* minimum */}
1288
- <TextField
1289
- type='text'
1290
- value={config.boxplot.labels.minimum}
1291
- fieldName='minimum'
1292
- section='boxplot'
1293
- subsection='labels'
1294
- label='Minimum'
1295
- updateField={updateField}
1296
- tooltip={
1297
- <Tooltip style={{ textTransform: 'none' }}>
1298
- <Tooltip.Target>
1299
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1300
- </Tooltip.Target>
1301
- <Tooltip.Content>
1302
- <p>Lowest value, excluding outliers</p>
1303
- </Tooltip.Content>
1304
- </Tooltip>
1305
- }
1306
- />
1307
- <br />
1308
- <h4 style={{ fontSize: '18px' }}>Labels for Additional Measures</h4>
1538
+ <TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='max value' placeholder='Auto' updateField={updateField} />
1539
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1540
+ <TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />
1541
+ <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1542
+ </>
1543
+ )
1544
+ )}
1545
+
1546
+ {/* start: anchors */}
1547
+ {visHasAnchors() && config.orientation !== 'horizontal' && (
1548
+ <div className='edit-block'>
1549
+ <h3>Anchors</h3>
1550
+ <Accordion allowZeroExpanded>
1551
+ {config.yAxis?.anchors?.map((anchor, index) => (
1552
+ <AccordionItem className='series-item series-item--chart'>
1553
+ <AccordionItemHeading className='series-item__title'>
1554
+ <>
1555
+ <AccordionItemButton className={'accordion__button accordion__button'}>
1556
+ Anchor {index + 1}
1557
+ <button
1558
+ className='series-list__remove'
1559
+ onClick={e => {
1560
+ e.preventDefault()
1561
+ const copiedAnchorGroups = [...config.yAxis.anchors]
1562
+ copiedAnchorGroups.splice(index, 1)
1563
+ updateConfig({
1564
+ ...config,
1565
+ yAxis: {
1566
+ ...config.yAxis,
1567
+ anchors: copiedAnchorGroups
1568
+ }
1569
+ })
1570
+ }}
1571
+ >
1572
+ Remove
1573
+ </button>
1574
+ </AccordionItemButton>
1575
+ </>
1576
+ </AccordionItemHeading>
1577
+ <AccordionItemPanel>
1578
+ <label>
1579
+ <span>Anchor Value</span>
1580
+ <Tooltip style={{ textTransform: 'none' }}>
1581
+ <Tooltip.Target>
1582
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1583
+ </Tooltip.Target>
1584
+ <Tooltip.Content>
1585
+ <p>Enter the value as its shown in the data column</p>
1586
+ </Tooltip.Content>
1587
+ </Tooltip>
1588
+ <input
1589
+ type='text'
1590
+ value={config.yAxis.anchors[index].value ? config.yAxis.anchors[index].value : ''}
1591
+ onChange={e => {
1592
+ e.preventDefault()
1593
+ const copiedAnchors = [...config.yAxis.anchors]
1594
+ copiedAnchors[index].value = e.target.value
1595
+ updateConfig({
1596
+ ...config,
1597
+ yAxis: {
1598
+ ...config.yAxis,
1599
+ anchors: copiedAnchors
1600
+ }
1601
+ })
1602
+ }}
1603
+ />
1604
+ </label>
1309
1605
 
1310
- {/* iqr */}
1311
- <TextField type='text' value={config.boxplot.labels.iqr} fieldName='iqr' section='boxplot' subsection='labels' label='Interquartile Range' updateField={updateField} />
1606
+ <label>
1607
+ <span>Anchor Color</span>
1608
+ <input
1609
+ type='text'
1610
+ value={config.yAxis.anchors[index].color ? config.yAxis.anchors[index].color : ''}
1611
+ onChange={e => {
1612
+ e.preventDefault()
1613
+ const copiedAnchors = [...config.yAxis.anchors]
1614
+ copiedAnchors[index].color = e.target.value
1615
+ updateConfig({
1616
+ ...config,
1617
+ yAxis: {
1618
+ ...config.yAxis,
1619
+ anchors: copiedAnchors
1620
+ }
1621
+ })
1622
+ }}
1623
+ />
1624
+ </label>
1625
+
1626
+ <label>
1627
+ Anchor Line Style
1628
+ <select
1629
+ value={config.yAxis.anchors[index].lineStyle || ''}
1630
+ onChange={e => {
1631
+ const copiedAnchors = [...config.yAxis.anchors]
1632
+ copiedAnchors[index].lineStyle = e.target.value
1633
+ updateConfig({
1634
+ ...config,
1635
+ yAxis: {
1636
+ ...config.yAxis,
1637
+ anchors: copiedAnchors
1638
+ }
1639
+ })
1640
+ }}
1641
+ >
1642
+ <option>Select</option>
1643
+ {lineOptions.map(line => (
1644
+ <option key={line.key}>{line.value}</option>
1645
+ ))}
1646
+ </select>
1647
+ </label>
1648
+ </AccordionItemPanel>
1649
+ </AccordionItem>
1650
+ ))}
1651
+ </Accordion>
1652
+
1653
+ <button
1654
+ className='btn full-width'
1655
+ onClick={e => {
1656
+ e.preventDefault()
1657
+ const anchors = [...config.yAxis.anchors]
1658
+ anchors.push({})
1659
+ updateConfig({
1660
+ ...config,
1661
+ yAxis: {
1662
+ ...config.yAxis,
1663
+ anchors
1664
+ }
1665
+ })
1666
+ }}
1667
+ >
1668
+ Add Anchor
1669
+ </button>
1670
+ </div>
1671
+ )}
1672
+
1673
+ {visHasAnchors() && config.orientation === 'horizontal' && (
1674
+ <div className='edit-block'>
1675
+ <h3>Anchors</h3>
1676
+ <Accordion allowZeroExpanded>
1677
+ {config.xAxis?.anchors?.map((anchor, index) => (
1678
+ <AccordionItem className='series-item series-item--chart'>
1679
+ <AccordionItemHeading className='series-item__title'>
1680
+ <>
1681
+ <AccordionItemButton className={'accordion__button accordion__button'}>
1682
+ Anchor {index + 1}
1683
+ <button
1684
+ className='series-list__remove'
1685
+ onClick={e => {
1686
+ e.preventDefault()
1687
+ const copiedAnchorGroups = [...config.xAxis.anchors]
1688
+ copiedAnchorGroups.splice(index, 1)
1689
+ updateConfig({
1690
+ ...config,
1691
+ xAxis: {
1692
+ ...config.xAxis,
1693
+ anchors: copiedAnchorGroups
1694
+ }
1695
+ })
1696
+ }}
1697
+ >
1698
+ Remove
1699
+ </button>
1700
+ </AccordionItemButton>
1701
+ </>
1702
+ </AccordionItemHeading>
1703
+ <AccordionItemPanel>
1704
+ <label>
1705
+ <span>Anchor Value</span>
1706
+ <Tooltip style={{ textTransform: 'none' }}>
1707
+ <Tooltip.Target>
1708
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1709
+ </Tooltip.Target>
1710
+ <Tooltip.Content>
1711
+ <p>Enter the value as its shown in the data column</p>
1712
+ </Tooltip.Content>
1713
+ </Tooltip>
1714
+ <input
1715
+ type='text'
1716
+ value={config.xAxis.anchors[index].value ? config.xAxis.anchors[index].value : ''}
1717
+ onChange={e => {
1718
+ e.preventDefault()
1719
+ const copiedAnchors = [...config.xAxis.anchors]
1720
+ copiedAnchors[index].value = e.target.value
1721
+ updateConfig({
1722
+ ...config,
1723
+ xAxis: {
1724
+ ...config.xAxis,
1725
+ anchors: copiedAnchors
1726
+ }
1727
+ })
1728
+ }}
1729
+ />
1730
+ </label>
1312
1731
 
1313
- {/* count */}
1314
- <TextField type='text' value={config.boxplot.labels.total} fieldName='total' section='boxplot' subsection='labels' label='Total' updateField={updateField} />
1732
+ <label>
1733
+ <span>Anchor Color</span>
1734
+ <input
1735
+ type='text'
1736
+ value={config.xAxis.anchors[index].color ? config.xAxis.anchors[index].color : ''}
1737
+ onChange={e => {
1738
+ e.preventDefault()
1739
+ const copiedAnchors = [...config.xAxis.anchors]
1740
+ copiedAnchors[index].color = e.target.value
1741
+ updateConfig({
1742
+ ...config,
1743
+ xAxis: {
1744
+ ...config.xAxis,
1745
+ anchors: copiedAnchors
1746
+ }
1747
+ })
1748
+ }}
1749
+ />
1750
+ </label>
1315
1751
 
1316
- {/* mean */}
1317
- <TextField type='text' value={config.boxplot.labels.mean} fieldName='mean' section='boxplot' subsection='labels' label='Mean' updateField={updateField} />
1318
- {/* outliers */}
1319
- <TextField type='text' value={config.boxplot.labels.outliers} fieldName='outliers' section='boxplot' subsection='labels' label='Outliers' updateField={updateField} />
1320
- {/* values */}
1321
- <TextField type='text' value={config.boxplot.labels.values} fieldName='values' section='boxplot' subsection='labels' label='Values' updateField={updateField} />
1322
- <br />
1323
- <h4 style={{ fontSize: '18px' }}>Percentages for Quartiles</h4>
1752
+ <label>
1753
+ Anchor Line Style
1754
+ <select
1755
+ value={config.xAxis.anchors[index].lineStyle || ''}
1756
+ onChange={e => {
1757
+ const copiedAnchors = [...config.xAxis.anchors]
1758
+ copiedAnchors[index].lineStyle = e.target.value
1759
+ updateConfig({
1760
+ ...config,
1761
+ xAxis: {
1762
+ ...config.xAxis,
1763
+ anchors: copiedAnchors
1764
+ }
1765
+ })
1766
+ }}
1767
+ >
1768
+ <option>Select</option>
1769
+ {lineOptions.map(line => (
1770
+ <option key={line.key}>{line.value}</option>
1771
+ ))}
1772
+ </select>
1773
+ </label>
1774
+ </AccordionItemPanel>
1775
+ </AccordionItem>
1776
+ ))}
1777
+ </Accordion>
1778
+
1779
+ <button
1780
+ className='btn full-width'
1781
+ onClick={e => {
1782
+ e.preventDefault()
1783
+ const anchors = [...config.xAxis.anchors]
1784
+ anchors.push({})
1785
+ updateConfig({
1786
+ ...config,
1787
+ xAxis: {
1788
+ ...config.xAxis,
1789
+ anchors
1790
+ }
1791
+ })
1792
+ }}
1793
+ >
1794
+ Add Anchor
1795
+ </button>
1796
+ </div>
1797
+ )}
1798
+ {/* end: anchors */}
1799
+ </AccordionItemPanel>
1800
+ </AccordionItem>
1801
+ {/* Right Value Axis Settings */}
1802
+ {hasRightAxis && (
1803
+ <AccordionItem>
1804
+ <AccordionItemHeading>
1805
+ <AccordionItemButton>Right Value Axis</AccordionItemButton>
1806
+ </AccordionItemHeading>
1807
+ <AccordionItemPanel>
1808
+ <TextField value={config.yAxis.rightLabel} section='yAxis' fieldName='rightLabel' label='Label' updateField={updateField} />
1809
+ <TextField value={config.yAxis.rightNumTicks} placeholder='Auto' type='number' section='yAxis' fieldName='rightNumTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1810
+ <TextField value={config.yAxis.rightAxisSize} type='number' section='yAxis' fieldName='rightAxisSize' label='Size (Width)' className='number-narrow' updateField={updateField} />
1811
+ <TextField value={config.yAxis.rightLabelOffsetSize} type='number' section='yAxis' fieldName='rightLabelOffsetSize' label='Label Offset' className='number-narrow' updateField={updateField} />
1812
+
1813
+ <span className='divider-heading'>Number Formatting</span>
1814
+ <CheckBox value={config.dataFormat.rightCommas} section='dataFormat' fieldName='rightCommas' label='Add commas' updateField={updateField} />
1815
+ <TextField value={config.dataFormat.rightRoundTo} type='number' section='dataFormat' fieldName='rightRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1816
+ <div className='two-col-inputs'>
1324
1817
  <TextField
1325
- type='number'
1326
- value={config.boxplot.firstQuartilePercentage ? config.boxplot.firstQuartilePercentage : 25}
1327
- fieldName='firstQuartilePercentage'
1328
- section='boxplot'
1329
- label='Lower Quartile'
1330
- max={100}
1818
+ value={config.dataFormat.rightPrefix}
1819
+ section='dataFormat'
1820
+ fieldName='rightPrefix'
1821
+ label='Prefix'
1331
1822
  updateField={updateField}
1332
1823
  tooltip={
1333
1824
  <Tooltip style={{ textTransform: 'none' }}>
@@ -1335,19 +1826,17 @@ const EditorPanel = () => {
1335
1826
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1336
1827
  </Tooltip.Target>
1337
1828
  <Tooltip.Content>
1338
- <p>Represented by bottom line of box. 25% of data are lower.</p>
1829
+ {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1830
+ {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
1339
1831
  </Tooltip.Content>
1340
1832
  </Tooltip>
1341
1833
  }
1342
1834
  />
1343
-
1344
1835
  <TextField
1345
- type='number'
1346
- value={config.boxplot.thirdQuartilePercentage ? config.boxplot.thirdQuartilePercentage : 75}
1347
- fieldName='thirdQuartilePercentage'
1348
- label='Upper Quartile'
1349
- section='boxplot'
1350
- max={100}
1836
+ value={config.dataFormat.rightSuffix}
1837
+ section='dataFormat'
1838
+ fieldName='rightSuffix'
1839
+ label='Suffix'
1351
1840
  updateField={updateField}
1352
1841
  tooltip={
1353
1842
  <Tooltip style={{ textTransform: 'none' }}>
@@ -1355,29 +1844,36 @@ const EditorPanel = () => {
1355
1844
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1356
1845
  </Tooltip.Target>
1357
1846
  <Tooltip.Content>
1358
- <p>Represented by top line of box. 25% of data are higher.</p>
1847
+ {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1848
+ {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1359
1849
  </Tooltip.Content>
1360
1850
  </Tooltip>
1361
1851
  }
1362
1852
  />
1363
- </AccordionItemPanel>
1364
- </AccordionItem>
1365
- )}
1853
+ </div>
1366
1854
 
1367
- <AccordionItem>
1368
- <AccordionItemHeading>
1369
- <AccordionItemButton>
1370
- {config.visualizationType !== 'Pie' ? (config.orientation !== 'horizontal' ? 'Left Value Axis' : 'Value Axis') : 'Data Format'}
1371
- {config.visualizationType === 'Pie' && !config.yAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1372
- </AccordionItemButton>
1373
- </AccordionItemHeading>
1374
- <AccordionItemPanel>
1375
- {config.visualizationType === 'Pie' && (
1855
+ <CheckBox value={config.yAxis.rightHideAxis} section='yAxis' fieldName='rightHideAxis' label='Hide Axis' updateField={updateField} />
1856
+ <CheckBox value={config.yAxis.rightHideLabel} section='yAxis' fieldName='rightHideLabel' label='Hide Label' updateField={updateField} />
1857
+ <CheckBox value={config.yAxis.rightHideTicks} section='yAxis' fieldName='rightHideTicks' label='Hide Ticks' updateField={updateField} />
1858
+ </AccordionItemPanel>
1859
+ </AccordionItem>
1860
+ )}
1861
+ <AccordionItem>
1862
+ <AccordionItemHeading>
1863
+ <AccordionItemButton>
1864
+ {config.visualizationType !== 'Pie' ? (config.visualizationType === 'Bar' ? 'Date/Category Axis' : 'Date/Category Axis') : 'Segments'}
1865
+ {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1866
+ </AccordionItemButton>
1867
+ </AccordionItemHeading>
1868
+ <AccordionItemPanel>
1869
+ {config.visualizationType !== 'Pie' && (
1870
+ <>
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']} />
1376
1872
  <Select
1377
- value={config.yAxis.dataKey || ''}
1378
- section='yAxis'
1873
+ value={config.xAxis.dataKey || setCategoryAxis() || ''}
1874
+ section='xAxis'
1379
1875
  fieldName='dataKey'
1380
- label='Data Column'
1876
+ label='Data Key'
1381
1877
  initial='Select'
1382
1878
  required={true}
1383
1879
  updateField={updateField}
@@ -1388,484 +1884,724 @@ const EditorPanel = () => {
1388
1884
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1389
1885
  </Tooltip.Target>
1390
1886
  <Tooltip.Content>
1391
- <p>Select the source data to be visually represented.</p>
1887
+ <p>Select the column or row containing the categories or dates for this axis. </p>
1392
1888
  </Tooltip.Content>
1393
1889
  </Tooltip>
1394
1890
  }
1395
1891
  />
1396
- )}
1397
- {config.visualizationType !== 'Pie' && (
1398
- <>
1399
- <TextField value={config.yAxis.label} section='yAxis' fieldName='label' label='Label' updateField={updateField} />
1400
- {config.runtime.seriesKeys && config.runtime.seriesKeys.length === 1 && config.visualizationType !== 'Box Plot' && <CheckBox value={config.isLegendValue} fieldName='isLegendValue' label='Use Legend Value in Hover' updateField={updateField} />}
1401
- <TextField value={config.yAxis.numTicks} placeholder='Auto' type='number' section='yAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1402
- {config.visualizationType === 'Paired Bar' && <TextField value={config.yAxis.tickRotation || 0} type='number' min='0' section='yAxis' fieldName='tickRotation' label='Tick rotation (Degrees)' className='number-narrow' updateField={updateField} />}
1403
- <TextField
1404
- value={config.yAxis.size}
1405
- type='number'
1406
- section='yAxis'
1407
- fieldName='size'
1408
- label={config.orientation === 'horizontal' ? 'Size (Height)' : 'Size (Width)'}
1409
- className='number-narrow'
1410
- updateField={updateField}
1411
- tooltip={
1412
- <Tooltip style={{ textTransform: 'none' }}>
1413
- <Tooltip.Target>
1414
- <Icon display='question' />
1415
- </Tooltip.Target>
1416
- <Tooltip.Content>
1417
- <p>{`Increase the size if elements in the ${config.orientation} axis are being crowded or hidden behind other elements. Decrease if less space is required for the value axis.`}</p>
1418
- </Tooltip.Content>
1419
- </Tooltip>
1420
- }
1421
- />
1422
- {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
1423
- {/* <TextField value={config.yAxis.axisPadding} type='number' max={10} min={0} section='yAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
1424
- {config.orientation === 'horizontal' && <TextField value={config.xAxis.labelOffset} section='xAxis' fieldName='labelOffset' label='Label offset' type='number' className='number-narrow' updateField={updateField} />}
1425
- {config.orientation !== 'horizontal' && <CheckBox value={config.yAxis.gridLines} section='yAxis' fieldName='gridLines' label='Display Gridlines' updateField={updateField} />}
1426
- <CheckBox value={config.yAxis.enablePadding} section='yAxis' fieldName='enablePadding' label='Add Padding to Value Axis Scale' updateField={updateField} />
1427
- </>
1428
- )}
1429
- <span className='divider-heading'>Number Formatting</span>
1430
- <CheckBox value={config.dataFormat.commas} section='dataFormat' fieldName='commas' label='Add commas' updateField={updateField} />
1431
- <CheckBox
1432
- value={config.dataFormat.abbreviated}
1433
- section='dataFormat'
1434
- fieldName='abbreviated'
1435
- label='Abbreviate Axis Values'
1892
+ </>
1893
+ )}
1894
+
1895
+ {config.visualizationType === 'Pie' && (
1896
+ <Select
1897
+ value={config.xAxis.dataKey || ''}
1898
+ section='xAxis'
1899
+ fieldName='dataKey'
1900
+ label='Segment Labels'
1901
+ initial='Select'
1902
+ required={true}
1436
1903
  updateField={updateField}
1904
+ options={getColumns(false)}
1437
1905
  tooltip={
1438
1906
  <Tooltip style={{ textTransform: 'none' }}>
1439
1907
  <Tooltip.Target>
1440
- <Icon display='question' />
1908
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1441
1909
  </Tooltip.Target>
1442
1910
  <Tooltip.Content>
1443
- <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
1911
+ <p>Select the source row or column that contains the segment labels. Depending on the data structure, it may be listed as "Key."</p>
1444
1912
  </Tooltip.Content>
1445
1913
  </Tooltip>
1446
1914
  }
1447
1915
  />
1448
- <TextField value={config.dataFormat.roundTo} type='number' section='dataFormat' fieldName='roundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1449
- <div className='two-col-inputs'>
1450
- <TextField
1451
- value={config.dataFormat.prefix}
1452
- section='dataFormat'
1453
- fieldName='prefix'
1454
- label='Prefix'
1455
- updateField={updateField}
1916
+ )}
1917
+
1918
+ {config.visualizationType !== 'Pie' && (
1919
+ <>
1920
+ <TextField value={config.xAxis.label} section='xAxis' fieldName='label' label='Label' updateField={updateField} />
1921
+
1922
+ {config.xAxis.type === 'continuous' && (
1923
+ <>
1924
+ <TextField
1925
+ value={config.dataFormat.bottomPrefix}
1926
+ section='dataFormat'
1927
+ fieldName='bottomPrefix'
1928
+ label='Prefix'
1929
+ updateField={updateField}
1930
+ tooltip={
1931
+ <Tooltip style={{ textTransform: 'none' }}>
1932
+ <Tooltip.Target>
1933
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1934
+ </Tooltip.Target>
1935
+ <Tooltip.Content>
1936
+ {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1937
+ {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1938
+ </Tooltip.Content>
1939
+ </Tooltip>
1940
+ }
1941
+ />
1942
+
1943
+ <TextField
1944
+ value={config.dataFormat.bottomSuffix}
1945
+ section='dataFormat'
1946
+ fieldName='bottomSuffix'
1947
+ label='Suffix'
1948
+ updateField={updateField}
1949
+ tooltip={
1950
+ <Tooltip style={{ textTransform: 'none' }}>
1951
+ <Tooltip.Target>
1952
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1953
+ </Tooltip.Target>
1954
+ <Tooltip.Content>
1955
+ {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1956
+ {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1957
+ </Tooltip.Content>
1958
+ </Tooltip>
1959
+ }
1960
+ />
1961
+
1962
+ <CheckBox
1963
+ value={config.dataFormat.bottomAbbreviated}
1964
+ section='dataFormat'
1965
+ fieldName='bottomAbbreviated'
1966
+ label='Abbreviate Axis Values'
1967
+ updateField={updateField}
1968
+ tooltip={
1969
+ <Tooltip style={{ textTransform: 'none' }}>
1970
+ <Tooltip.Target>
1971
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1972
+ </Tooltip.Target>
1973
+ <Tooltip.Content>
1974
+ <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
1975
+ </Tooltip.Content>
1976
+ </Tooltip>
1977
+ }
1978
+ />
1979
+ </>
1980
+ )}
1981
+
1982
+ {config.xAxis.type === 'date' && (
1983
+ <>
1984
+ <p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
1985
+ Format how charts should parse and display your dates using{' '}
1986
+ <a href='https://github.com/d3/d3-time-format#locale_format' target='_blank' rel='noreferrer'>
1987
+ these guidelines
1988
+ </a>
1989
+ .
1990
+ </p>
1991
+ <TextField value={config.xAxis.dateParseFormat} section='xAxis' fieldName='dateParseFormat' placeholder='Ex. %Y-%m-%d' label='Date Parse Format' updateField={updateField} />
1992
+ <TextField value={config.xAxis.dateDisplayFormat} section='xAxis' fieldName='dateDisplayFormat' placeholder='Ex. %Y-%m-%d' label='Date Display Format' updateField={updateField} />
1993
+ </>
1994
+ )}
1995
+
1996
+ <CheckBox
1997
+ value={config.exclusions.active}
1998
+ section='exclusions'
1999
+ fieldName='active'
2000
+ label={config.xAxis.type === 'date' ? 'Limit by start and/or end dates' : 'Exclude one or more values'}
1456
2001
  tooltip={
1457
2002
  <Tooltip style={{ textTransform: 'none' }}>
1458
2003
  <Tooltip.Target>
1459
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2004
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1460
2005
  </Tooltip.Target>
1461
2006
  <Tooltip.Content>
1462
- {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1463
- {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
2007
+ <p>When this option is checked, you can select source-file values for exclusion from the date/category axis. </p>
1464
2008
  </Tooltip.Content>
1465
2009
  </Tooltip>
1466
2010
  }
1467
- />
1468
- <TextField
1469
- value={config.dataFormat.suffix}
1470
- section='dataFormat'
1471
- fieldName='suffix'
1472
- label='Suffix'
1473
2011
  updateField={updateField}
1474
- tooltip={
1475
- <Tooltip style={{ textTransform: 'none' }}>
1476
- <Tooltip.Target>
1477
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1478
- </Tooltip.Target>
1479
- <Tooltip.Content>
1480
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1481
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1482
- </Tooltip.Content>
1483
- </Tooltip>
1484
- }
1485
2012
  />
1486
- </div>
1487
2013
 
1488
- {config.orientation === 'horizontal' ? ( // horizontal - x is vertical y is horizontal
1489
- <>
1490
- <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1491
- <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1492
- <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1493
- <TextField value={config.xAxis.max} section='xAxis' fieldName='max' label='max value' type='number' placeholder='Auto' updateField={updateField} />
1494
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1495
- <TextField value={config.xAxis.min} section='xAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />
1496
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
1497
- {config.visualizationType === 'Deviation Bar' && (
1498
- <>
1499
- <TextField value={config.xAxis.target} section='xAxis' fieldName='target' type='number' label='Deviation point' placeholder='Auto' updateField={updateField} />
1500
- <TextField value={config.xAxis.targetLabel || 'Target'} section='xAxis' fieldName='targetLabel' type='text' label='Deviation point Label' updateField={updateField} />
1501
- <CheckBox value={config.xAxis.showTargetLabel} section='xAxis' fieldName='showTargetLabel' label='Display Deviation point label' updateField={updateField} />
1502
- </>
1503
- )}
1504
- </>
1505
- ) : (
1506
- config.visualizationType !== 'Pie' && (
2014
+ {config.exclusions.active && (
1507
2015
  <>
1508
- <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1509
- <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1510
- <CheckBox value={config.yAxis.hideTicks} section='yAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1511
- <TextField value={config.yAxis.max} section='yAxis' fieldName='max' type='number' label='max value' placeholder='Auto' updateField={updateField} />
1512
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.maxMsg}</span>
1513
- <TextField value={config.yAxis.min} section='yAxis' fieldName='min' type='number' label='min value' placeholder='Auto' updateField={updateField} />
1514
- <span style={{ color: 'red', display: 'block' }}>{warningMsg.minMsg}</span>
2016
+ {config.xAxis.type === 'categorical' && (
2017
+ <>
2018
+ {config.exclusions.keys.length > 0 && (
2019
+ <>
2020
+ <fieldset>
2021
+ <legend className='edit-label'>Excluded Keys</legend>
2022
+ </fieldset>
2023
+ <ExclusionsList />
2024
+ </>
2025
+ )}
2026
+
2027
+ <Select
2028
+ fieldName='visualizationType'
2029
+ label='Add Exclusion'
2030
+ initial='Select'
2031
+ onChange={e => {
2032
+ if (e.target.value !== '' && e.target.value !== 'Select') {
2033
+ addNewExclusion(e.target.value)
2034
+ }
2035
+ e.target.value = ''
2036
+ }}
2037
+ options={getDataValues(config.xAxis.dataKey, true)}
2038
+ />
2039
+ </>
2040
+ )}
2041
+
2042
+ {config.xAxis.type === 'date' && (
2043
+ <>
2044
+ <TextField type='date' section='exclusions' fieldName='dateStart' label='Start Date' updateField={updateField} value={config.exclusions.dateStart || ''} />
2045
+ <TextField type='date' section='exclusions' fieldName='dateEnd' label='End Date' updateField={updateField} value={config.exclusions.dateEnd || ''} />
2046
+ </>
2047
+ )}
1515
2048
  </>
1516
- )
1517
- )}
1518
- </AccordionItemPanel>
1519
- </AccordionItem>
2049
+ )}
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} />
1520
2051
 
1521
- {/* Right Value Axis Settings */}
1522
- {hasRightAxis && (
1523
- <AccordionItem>
1524
- <AccordionItemHeading>
1525
- <AccordionItemButton>Right Value Axis</AccordionItemButton>
1526
- </AccordionItemHeading>
1527
- <AccordionItemPanel>
1528
- <TextField value={config.yAxis.rightLabel} section='yAxis' fieldName='rightLabel' label='Label' updateField={updateField} />
1529
- <TextField value={config.yAxis.rightNumTicks} placeholder='Auto' type='number' section='yAxis' fieldName='rightNumTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1530
- <TextField value={config.yAxis.rightAxisSize} type='number' section='yAxis' fieldName='rightAxisSize' label='Size (Width)' className='number-narrow' updateField={updateField} />
1531
- <TextField value={config.yAxis.rightLabelOffsetSize} type='number' section='yAxis' fieldName='rightLabelOffsetSize' label='Label Offset' className='number-narrow' updateField={updateField} />
1532
-
1533
- <span className='divider-heading'>Number Formatting</span>
1534
- <CheckBox value={config.dataFormat.rightCommas} section='dataFormat' fieldName='rightCommas' label='Add commas' updateField={updateField} />
1535
- <TextField value={config.dataFormat.rightRoundTo} type='number' section='dataFormat' fieldName='rightRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1536
- <div className='two-col-inputs'>
1537
- <TextField
1538
- value={config.dataFormat.rightPrefix}
1539
- section='dataFormat'
1540
- fieldName='rightPrefix'
1541
- label='Prefix'
1542
- updateField={updateField}
1543
- tooltip={
1544
- <Tooltip style={{ textTransform: 'none' }}>
1545
- <Tooltip.Target>
1546
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1547
- </Tooltip.Target>
1548
- <Tooltip.Content>
1549
- {config.visualizationType === 'Pie' && <p>Enter a data prefix to display in the data table and chart tooltips, if applicable.</p>}
1550
- {config.visualizationType !== 'Pie' && <p>Enter a data prefix (such as "$"), if applicable.</p>}
1551
- </Tooltip.Content>
1552
- </Tooltip>
1553
- }
1554
- />
1555
- <TextField
1556
- value={config.dataFormat.rightSuffix}
1557
- section='dataFormat'
1558
- fieldName='rightSuffix'
1559
- label='Suffix'
1560
- updateField={updateField}
1561
- tooltip={
1562
- <Tooltip style={{ textTransform: 'none' }}>
1563
- <Tooltip.Target>
1564
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1565
- </Tooltip.Target>
1566
- <Tooltip.Content>
1567
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1568
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1569
- </Tooltip.Content>
1570
- </Tooltip>
1571
- }
1572
- />
1573
- </div>
2052
+ <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} />
1574
2053
 
1575
- <CheckBox value={config.yAxis.rightHideAxis} section='yAxis' fieldName='rightHideAxis' label='Hide Axis' updateField={updateField} />
1576
- <CheckBox value={config.yAxis.rightHideLabel} section='yAxis' fieldName='rightHideLabel' label='Hide Label' updateField={updateField} />
1577
- <CheckBox value={config.yAxis.rightHideTicks} section='yAxis' fieldName='rightHideTicks' label='Hide Ticks' updateField={updateField} />
1578
- </AccordionItemPanel>
1579
- </AccordionItem>
1580
- )}
2054
+ {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
2055
+ {/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
1581
2056
 
1582
- <AccordionItem>
1583
- <AccordionItemHeading>
1584
- <AccordionItemButton>
1585
- {config.visualizationType !== 'Pie' ? (config.visualizationType === 'Bar' ? 'Date/Category Axis' : 'Date/Category Axis') : 'Segments'}
1586
- {!config.xAxis.dataKey && <WarningImage width='25' className='warning-icon' />}
1587
- </AccordionItemButton>
1588
- </AccordionItemHeading>
1589
- <AccordionItemPanel>
1590
- {config.visualizationType !== 'Pie' && (
1591
- <>
1592
- <Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={config.visualizationType !== 'Scatter Plot' ? ['categorical', 'date'] : ['categorical', 'continuous', 'date']} />
1593
- <Select
1594
- value={config.xAxis.dataKey || setCategoryAxis() || ''}
1595
- section='xAxis'
1596
- fieldName='dataKey'
1597
- label='Data Key'
1598
- initial='Select'
1599
- required={true}
1600
- updateField={updateField}
1601
- options={getColumns(false)}
1602
- tooltip={
1603
- <Tooltip style={{ textTransform: 'none' }}>
1604
- <Tooltip.Target>
1605
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1606
- </Tooltip.Target>
1607
- <Tooltip.Content>
1608
- <p>Select the column or row containing the categories or dates for this axis. </p>
1609
- </Tooltip.Content>
1610
- </Tooltip>
1611
- }
1612
- />
1613
- </>
1614
- )}
2057
+ {config.xAxis.type === 'continuous' && (
2058
+ <>
2059
+ <CheckBox value={config.dataFormat.bottomCommas} section='dataFormat' fieldName='bottomCommas' label='Add commas' updateField={updateField} />
2060
+ <TextField value={config.dataFormat.bottomRoundTo} type='number' section='dataFormat' fieldName='bottomRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
2061
+ </>
2062
+ )}
1615
2063
 
1616
- {config.visualizationType === 'Pie' && (
1617
- <Select
1618
- value={config.xAxis.dataKey || ''}
1619
- section='xAxis'
1620
- fieldName='dataKey'
1621
- label='Segment Labels'
1622
- initial='Select'
1623
- required={true}
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
+ {config.orientation === 'horizontal' ? (
2066
+ <>
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} />
2069
+ </>
2070
+ ) : (
2071
+ <>
2072
+ <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
2073
+ <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
2074
+ <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
2075
+ </>
2076
+ )}
2077
+
2078
+ {config.series?.length === 1 && config.visualizationType === 'Bar' && (
2079
+ <>
2080
+ {/* HIGHLIGHTED BARS */}
2081
+ <label htmlFor='barHighlight'>Bar Highlighting</label>
2082
+ {config.series.length === 1 &&
2083
+ highlightedBarValues.map((highlightedBarValue, i) => (
2084
+ <fieldset>
2085
+ <div className='edit-block' key={`highlighted-bar-${i}`}>
2086
+ <button className='remove-column' onClick={e => handleRemoveHighlightedBar(e, i)}>
2087
+ Remove
2088
+ </button>
2089
+ <p>Highlighted Bar {i + 1}</p>
2090
+ <label>
2091
+ <span className='edit-label column-heading'>Value</span>
2092
+ <select value={config.highlightedBarValues[i].value} onChange={e => handleUpdateHighlightedBar(e, i)}>
2093
+ <option value=''>- Select Value -</option>
2094
+ {highlightedSeriesValues && [...new Set(highlightedSeriesValues)].sort().map(option => <option key={`special-class-value-option-${i}-${option}`}>{option}</option>)}
2095
+ </select>
2096
+ </label>
2097
+ <label>
2098
+ <span className='edit-label column-heading'>Color</span>
2099
+ <input type='text' value={config.highlightedBarValues[i].color ? config.highlightedBarValues[i].color : ''} onChange={e => handleUpdateHighlightedBarColor(e, i)} />
2100
+ </label>
2101
+ <label>
2102
+ <span className='edit-label column-heading'>Border Width</span>
2103
+ <input max='5' min='0' type='number' value={config.highlightedBarValues[i].borderWidth ? config.highlightedBarValues[i].borderWidth : ''} onChange={e => handleUpdateHighlightedBorderWidth(e, i)} />
2104
+ </label>
2105
+ <label>
2106
+ <span className='edit-label column-heading'>Legend Label</span>
2107
+ <input type='text' value={config.highlightedBarValues[i].legendLabel ? config.highlightedBarValues[i].legendLabel : ''} onChange={e => handleHighlightedBarLegendLabel(e, i)} />
2108
+ </label>
2109
+ </div>
2110
+ </fieldset>
2111
+ ))}
2112
+ <button className='btn full-width' onClick={e => handleAddNewHighlightedBar(e)}>
2113
+ Add Highlighted Bar
2114
+ </button>
2115
+ </>
2116
+ )}
2117
+ </>
2118
+ )}
2119
+
2120
+ {config.visualizationType === 'Pie' && (
2121
+ <>
2122
+ <CheckBox
2123
+ value={config.exclusions.active}
2124
+ section='exclusions'
2125
+ fieldName='active'
2126
+ label={'Exclude one or more values'}
1624
2127
  updateField={updateField}
1625
- options={getColumns(false)}
1626
2128
  tooltip={
1627
2129
  <Tooltip style={{ textTransform: 'none' }}>
1628
2130
  <Tooltip.Target>
1629
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2131
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
1630
2132
  </Tooltip.Target>
1631
2133
  <Tooltip.Content>
1632
- <p>Select the source row or column that contains the segment labels. Depending on the data structure, it may be listed as "Key."</p>
2134
+ <p>When this option is checked, you can select values for exclusion from the pie segments.</p>
1633
2135
  </Tooltip.Content>
1634
2136
  </Tooltip>
1635
2137
  }
1636
2138
  />
1637
- )}
1638
-
1639
- {config.visualizationType !== 'Pie' && (
1640
- <>
1641
- <TextField value={config.xAxis.label} section='xAxis' fieldName='label' label='Label' updateField={updateField} />
1642
-
1643
- {config.xAxis.type === 'continuous' && (
1644
- <>
1645
- <TextField
1646
- value={config.dataFormat.bottomPrefix}
1647
- section='dataFormat'
1648
- fieldName='bottomPrefix'
1649
- label='Prefix'
1650
- updateField={updateField}
1651
- tooltip={
2139
+ {config.exclusions.active && (
2140
+ <>
2141
+ {config.exclusions.keys.length > 0 && (
2142
+ <>
2143
+ <fieldset>
2144
+ <legend className='edit-label'>Excluded Keys</legend>
2145
+ </fieldset>
2146
+ <ExclusionsList />
2147
+ </>
2148
+ )}
2149
+
2150
+ <Select
2151
+ fieldName='visualizationType'
2152
+ label='Add Exclusion'
2153
+ initial='Select'
2154
+ onChange={e => {
2155
+ if (e.target.value !== '' && e.target.value !== 'Select') {
2156
+ addNewExclusion(e.target.value)
2157
+ }
2158
+ e.target.value = ''
2159
+ }}
2160
+ options={getDataValues(config.xAxis.dataKey, true)}
2161
+ />
2162
+ </>
2163
+ )}
2164
+ </>
2165
+ )}
2166
+
2167
+ {/* anchors */}
2168
+ {visHasAnchors() && config.orientation !== 'horizontal' && (
2169
+ <div className='edit-block'>
2170
+ <h3>Anchors</h3>
2171
+ <Accordion allowZeroExpanded>
2172
+ {config.xAxis?.anchors?.map((anchor, index) => (
2173
+ <AccordionItem className='series-item series-item--chart'>
2174
+ <AccordionItemHeading className='series-item__title'>
2175
+ <>
2176
+ <AccordionItemButton className={'accordion__button accordion__button'}>
2177
+ Anchor {index + 1}
2178
+ <button
2179
+ className='series-list__remove'
2180
+ onClick={e => {
2181
+ e.preventDefault()
2182
+ const copiedAnchorGroups = [...config.xAxis.anchors]
2183
+ copiedAnchorGroups.splice(index, 1)
2184
+ updateConfig({
2185
+ ...config,
2186
+ xAxis: {
2187
+ ...config.xAxis,
2188
+ anchors: copiedAnchorGroups
2189
+ }
2190
+ })
2191
+ }}
2192
+ >
2193
+ Remove
2194
+ </button>
2195
+ </AccordionItemButton>
2196
+ </>
2197
+ </AccordionItemHeading>
2198
+ <AccordionItemPanel>
2199
+ <label>
2200
+ <span>Anchor Value</span>
1652
2201
  <Tooltip style={{ textTransform: 'none' }}>
1653
2202
  <Tooltip.Target>
1654
2203
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1655
2204
  </Tooltip.Target>
1656
2205
  <Tooltip.Content>
1657
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1658
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
2206
+ <p>Enter the value as its shown in the data column</p>
1659
2207
  </Tooltip.Content>
1660
2208
  </Tooltip>
1661
- }
1662
- />
1663
-
1664
- <TextField
1665
- value={config.dataFormat.bottomSuffix}
1666
- section='dataFormat'
1667
- fieldName='bottomSuffix'
1668
- label='Suffix'
1669
- updateField={updateField}
1670
- tooltip={
2209
+ <input
2210
+ type='text'
2211
+ value={config.xAxis.anchors[index].value ? config.xAxis.anchors[index].value : ''}
2212
+ onChange={e => {
2213
+ e.preventDefault()
2214
+ const copiedAnchors = [...config.xAxis.anchors]
2215
+ copiedAnchors[index].value = e.target.value
2216
+ updateConfig({
2217
+ ...config,
2218
+ xAxis: {
2219
+ ...config.xAxis,
2220
+ anchors: copiedAnchors
2221
+ }
2222
+ })
2223
+ }}
2224
+ />
2225
+ </label>
2226
+
2227
+ <label>
2228
+ <span>Anchor Color</span>
2229
+ <input
2230
+ type='text'
2231
+ value={config.xAxis.anchors[index].color ? config.xAxis.anchors[index].color : ''}
2232
+ onChange={e => {
2233
+ e.preventDefault()
2234
+ const copiedAnchors = [...config.xAxis.anchors]
2235
+ copiedAnchors[index].color = e.target.value
2236
+ updateConfig({
2237
+ ...config,
2238
+ xAxis: {
2239
+ ...config.xAxis,
2240
+ anchors: copiedAnchors
2241
+ }
2242
+ })
2243
+ }}
2244
+ />
2245
+ </label>
2246
+
2247
+ <label>
2248
+ Anchor Line Style
2249
+ <select
2250
+ value={config.xAxis.anchors[index].lineStyle || ''}
2251
+ onChange={e => {
2252
+ const copiedAnchors = [...config.xAxis.anchors]
2253
+ copiedAnchors[index].lineStyle = e.target.value
2254
+ updateConfig({
2255
+ ...config,
2256
+ xAxis: {
2257
+ ...config.xAxis,
2258
+ anchors: copiedAnchors
2259
+ }
2260
+ })
2261
+ }}
2262
+ >
2263
+ <option>Select</option>
2264
+ {lineOptions.map(line => (
2265
+ <option key={line.key}>{line.value}</option>
2266
+ ))}
2267
+ </select>
2268
+ </label>
2269
+ </AccordionItemPanel>
2270
+ </AccordionItem>
2271
+ ))}
2272
+ </Accordion>
2273
+
2274
+ <button
2275
+ className='btn full-width'
2276
+ onClick={e => {
2277
+ e.preventDefault()
2278
+ const anchors = [...config.xAxis.anchors]
2279
+ anchors.push({})
2280
+ updateConfig({
2281
+ ...config,
2282
+ xAxis: {
2283
+ ...config.xAxis,
2284
+ anchors
2285
+ }
2286
+ })
2287
+ }}
2288
+ >
2289
+ Add Anchor
2290
+ </button>
2291
+ </div>
2292
+ )}
2293
+
2294
+ {visHasAnchors() && config.orientation === 'horizontal' && (
2295
+ <div className='edit-block'>
2296
+ <h3>Anchors</h3>
2297
+ <Accordion allowZeroExpanded>
2298
+ {config.yAxis?.anchors?.map((anchor, index) => (
2299
+ <AccordionItem className='series-item series-item--chart'>
2300
+ <AccordionItemHeading className='series-item__title'>
2301
+ <>
2302
+ <AccordionItemButton className={'accordion__button accordion__button'}>
2303
+ Anchor {index + 1}
2304
+ <button
2305
+ className='series-list__remove'
2306
+ onClick={e => {
2307
+ e.preventDefault()
2308
+ const copiedAnchorGroups = [...config.yAxis.anchors]
2309
+ copiedAnchorGroups.splice(index, 1)
2310
+ updateConfig({
2311
+ ...config,
2312
+ yAxis: {
2313
+ ...config.yAxis,
2314
+ anchors: copiedAnchorGroups
2315
+ }
2316
+ })
2317
+ }}
2318
+ >
2319
+ Remove
2320
+ </button>
2321
+ </AccordionItemButton>
2322
+ </>
2323
+ </AccordionItemHeading>
2324
+ <AccordionItemPanel>
2325
+ <label>
2326
+ <span>Anchor Value</span>
1671
2327
  <Tooltip style={{ textTransform: 'none' }}>
1672
2328
  <Tooltip.Target>
1673
2329
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1674
2330
  </Tooltip.Target>
1675
2331
  <Tooltip.Content>
1676
- {config.visualizationType === 'Pie' && <p>Enter a data suffix to display in the data table and tooltips, if applicable.</p>}
1677
- {config.visualizationType !== 'Pie' && <p>Enter a data suffix (such as "%"), if applicable.</p>}
1678
- </Tooltip.Content>
1679
- </Tooltip>
1680
- }
1681
- />
1682
-
1683
- <CheckBox
1684
- value={config.dataFormat.bottomAbbreviated}
1685
- section='dataFormat'
1686
- fieldName='bottomAbbreviated'
1687
- label='Abbreviate Axis Values'
1688
- updateField={updateField}
1689
- tooltip={
1690
- <Tooltip style={{ textTransform: 'none' }}>
1691
- <Tooltip.Target>
1692
- <Icon display='question' />
1693
- </Tooltip.Target>
1694
- <Tooltip.Content>
1695
- <p>{`This option abbreviates very large or very small numbers on the value axis`}</p>
2332
+ <p>Enter the value as its shown in the data column</p>
1696
2333
  </Tooltip.Content>
1697
2334
  </Tooltip>
1698
- }
1699
- />
1700
- </>
1701
- )}
1702
-
1703
- {config.xAxis.type === 'date' && (
1704
- <>
1705
- <p style={{ padding: '1.5em 0 0.5em', fontSize: '.9rem', lineHeight: '1rem' }}>
1706
- Format how charts should parse and display your dates using{' '}
1707
- <a href='https://github.com/d3/d3-time-format#locale_format' target='_blank' rel='noreferrer'>
1708
- these guidelines
1709
- </a>
1710
- .
1711
- </p>
1712
- <TextField value={config.xAxis.dateParseFormat} section='xAxis' fieldName='dateParseFormat' placeholder='Ex. %Y-%m-%d' label='Date Parse Format' updateField={updateField} />
1713
- <TextField value={config.xAxis.dateDisplayFormat} section='xAxis' fieldName='dateDisplayFormat' placeholder='Ex. %Y-%m-%d' label='Date Display Format' updateField={updateField} />
1714
- </>
1715
- )}
1716
-
1717
- <CheckBox
1718
- value={config.exclusions.active}
1719
- section='exclusions'
1720
- fieldName='active'
1721
- label={config.xAxis.type === 'date' ? 'Limit by start and/or end dates' : 'Exclude one or more values'}
1722
- tooltip={
2335
+ <input
2336
+ type='text'
2337
+ value={config.yAxis.anchors[index].value ? config.yAxis.anchors[index].value : ''}
2338
+ onChange={e => {
2339
+ e.preventDefault()
2340
+ const copiedAnchors = [...config.yAxis.anchors]
2341
+ copiedAnchors[index].value = e.target.value
2342
+ updateConfig({
2343
+ ...config,
2344
+ yAxis: {
2345
+ ...config.yAxis,
2346
+ anchors: copiedAnchors
2347
+ }
2348
+ })
2349
+ }}
2350
+ />
2351
+ </label>
2352
+
2353
+ <label>
2354
+ <span>Anchor Color</span>
2355
+ <input
2356
+ type='text'
2357
+ value={config.yAxis.anchors[index].color ? config.yAxis.anchors[index].color : ''}
2358
+ onChange={e => {
2359
+ e.preventDefault()
2360
+ const copiedAnchors = [...config.yAxis.anchors]
2361
+ copiedAnchors[index].color = e.target.value
2362
+ updateConfig({
2363
+ ...config,
2364
+ yAxis: {
2365
+ ...config.yAxis,
2366
+ anchors: copiedAnchors
2367
+ }
2368
+ })
2369
+ }}
2370
+ />
2371
+ </label>
2372
+
2373
+ <label>
2374
+ Anchor Line Style
2375
+ <select
2376
+ value={config.yAxis.anchors[index].lineStyle || ''}
2377
+ onChange={e => {
2378
+ const copiedAnchors = [...config.yAxis.anchors]
2379
+ copiedAnchors[index].lineStyle = e.target.value
2380
+ updateConfig({
2381
+ ...config,
2382
+ yAxis: {
2383
+ ...config.yAxis,
2384
+ anchors: copiedAnchors
2385
+ }
2386
+ })
2387
+ }}
2388
+ >
2389
+ <option>Select</option>
2390
+ {lineOptions.map(line => (
2391
+ <option key={line.key}>{line.value}</option>
2392
+ ))}
2393
+ </select>
2394
+ </label>
2395
+ </AccordionItemPanel>
2396
+ </AccordionItem>
2397
+ ))}
2398
+ </Accordion>
2399
+
2400
+ <button
2401
+ className='btn full-width'
2402
+ onClick={e => {
2403
+ e.preventDefault()
2404
+ const anchors = [...config.yAxis.anchors]
2405
+ anchors.push({})
2406
+ updateConfig({
2407
+ ...config,
2408
+ yAxis: {
2409
+ ...config.yAxis,
2410
+ anchors
2411
+ }
2412
+ })
2413
+ }}
2414
+ >
2415
+ Add Anchor
2416
+ </button>
2417
+ </div>
2418
+ )}
2419
+ </AccordionItemPanel>
2420
+ </AccordionItem>
2421
+ {config.visualizationType !== 'Pie' && config.visualizationType !== 'Paired Bar' && (
2422
+ <AccordionItem>
2423
+ <AccordionItemHeading>
2424
+ <AccordionItemButton>Regions</AccordionItemButton>
2425
+ </AccordionItemHeading>
2426
+ <AccordionItemPanel>
2427
+ <Regions config={config} updateConfig={updateConfig} />
2428
+ </AccordionItemPanel>
2429
+ </AccordionItem>
2430
+ )}{' '}
2431
+ {/* Columns */}
2432
+ {config.visualizationType !== 'Box Plot' && config.table.showVertical && (
2433
+ <AccordionItem>
2434
+ <AccordionItemHeading>
2435
+ <AccordionItemButton>Columns</AccordionItemButton>
2436
+ </AccordionItemHeading>
2437
+ <AccordionItemPanel>
2438
+ {'navigation' !== config.type && (
2439
+ <fieldset className='primary-fieldset edit-block'>
2440
+ <label>
2441
+ <span className='edit-label'>
2442
+ Additional Columns
1723
2443
  <Tooltip style={{ textTransform: 'none' }}>
1724
2444
  <Tooltip.Target>
1725
2445
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1726
2446
  </Tooltip.Target>
1727
2447
  <Tooltip.Content>
1728
- <p>When this option is checked, you can select source-file values for exclusion from the date/category axis. </p>
2448
+ <p>You can specify additional columns to display in tooltips and / or the supporting data table.</p>
1729
2449
  </Tooltip.Content>
1730
2450
  </Tooltip>
1731
- }
1732
- updateField={updateField}
1733
- />
1734
-
1735
- {config.exclusions.active && (
1736
- <>
1737
- {config.xAxis.type === 'categorical' && (
1738
- <>
1739
- {config.exclusions.keys.length > 0 && (
1740
- <>
1741
- <fieldset>
1742
- <legend className='edit-label'>Excluded Keys</legend>
1743
- </fieldset>
1744
- <ExclusionsList />
1745
- </>
1746
- )}
1747
-
1748
- <Select
1749
- fieldName='visualizationType'
1750
- label='Add Exclusion'
1751
- initial='Select'
1752
- onChange={e => {
1753
- if (e.target.value !== '' && e.target.value !== 'Select') {
1754
- addNewExclusion(e.target.value)
1755
- }
1756
- e.target.value = ''
1757
- }}
1758
- options={getDataValues(config.xAxis.dataKey, true)}
1759
- />
1760
- </>
1761
- )}
1762
-
1763
- {config.xAxis.type === 'date' && (
1764
- <>
1765
- <TextField type='date' section='exclusions' fieldName='dateStart' label='Start Date' updateField={updateField} value={config.exclusions.dateStart || ''} />
1766
- <TextField type='date' section='exclusions' fieldName='dateEnd' label='End Date' updateField={updateField} value={config.exclusions.dateEnd || ''} />
1767
- </>
1768
- )}
1769
- </>
1770
- )}
1771
- <TextField value={config.xAxis.numTicks} placeholder='Auto' type='number' min='1' section='xAxis' fieldName='numTicks' label='Number of ticks' className='number-narrow' updateField={updateField} />
1772
-
1773
- <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} />
1774
-
1775
- {/* Hiding this for now, not interested in moving the axis lines away from chart comp. right now. */}
1776
- {/* <TextField value={config.xAxis.axisPadding} type='number' max={10} min={0} section='xAxis' fieldName='axisPadding' label={'Axis Padding'} className='number-narrow' updateField={updateField} /> */}
1777
-
1778
- {config.xAxis.type === 'continuous' && (
1779
- <>
1780
- <CheckBox value={config.dataFormat.bottomCommas} section='dataFormat' fieldName='bottomCommas' label='Add commas' updateField={updateField} />
1781
- <TextField value={config.dataFormat.bottomRoundTo} type='number' section='dataFormat' fieldName='bottomRoundTo' label='Round to decimal point' className='number-narrow' updateField={updateField} min={0} />
1782
- </>
1783
- )}
1784
-
1785
- {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} />}
1786
- {config.orientation === 'horizontal' ? (
1787
- <>
1788
- <CheckBox value={config.yAxis.hideAxis} section='yAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1789
- <CheckBox value={config.yAxis.hideLabel} section='yAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1790
- </>
1791
- ) : (
1792
- <>
1793
- <CheckBox value={config.xAxis.hideAxis} section='xAxis' fieldName='hideAxis' label='Hide Axis' updateField={updateField} />
1794
- <CheckBox value={config.xAxis.hideLabel} section='xAxis' fieldName='hideLabel' label='Hide Label' updateField={updateField} />
1795
- <CheckBox value={config.xAxis.hideTicks} section='xAxis' fieldName='hideTicks' label='Hide Ticks' updateField={updateField} />
1796
- </>
1797
- )}
1798
- </>
2451
+ </span>
2452
+ </label>
2453
+ {additionalColumns.map(val => (
2454
+ <fieldset className='edit-block' key={val}>
2455
+ <button
2456
+ className='remove-column'
2457
+ onClick={event => {
2458
+ event.preventDefault()
2459
+ removeAdditionalColumn(val)
2460
+ }}
2461
+ >
2462
+ Remove
2463
+ </button>
2464
+ <label>
2465
+ <span className='edit-label column-heading'>Column</span>
2466
+ <select
2467
+ value={config.columns[val] ? config.columns[val].name : columnsOptions[0]}
2468
+ onChange={event => {
2469
+ editColumn(val, 'name', event.target.value)
2470
+ }}
2471
+ >
2472
+ {columnsOptions}
2473
+ </select>
2474
+ </label>
2475
+ <TextField value={config.columns[val].label} section='columns' subsection={val} fieldName='label' label='Label' updateField={updateField} />
2476
+ <ul className='column-edit'>
2477
+ <li className='three-col'>
2478
+ <TextField value={config.columns[val].prefix} section='columns' subsection={val} fieldName='prefix' label='Prefix' updateField={updateField} />
2479
+ <TextField value={config.columns[val].suffix} section='columns' subsection={val} fieldName='suffix' label='Suffix' updateField={updateField} />
2480
+ <TextField type='number' value={config.columns[val].roundToPlace} section='columns' subsection={val} fieldName='roundToPlace' label='Round' updateField={updateField} />
2481
+ </li>
2482
+ <li>
2483
+ <label className='checkbox'>
2484
+ <input
2485
+ type='checkbox'
2486
+ checked={config.columns[val].useCommas}
2487
+ onChange={event => {
2488
+ editColumn(val, 'useCommas', event.target.checked)
2489
+ }}
2490
+ />
2491
+ <span className='edit-label'>Add Commas to Numbers</span>
2492
+ </label>
2493
+ </li>
2494
+ <li>
2495
+ <label className='checkbox'>
2496
+ <input
2497
+ type='checkbox'
2498
+ checked={config.columns[val].dataTable}
2499
+ onChange={event => {
2500
+ editColumn(val, 'dataTable', event.target.checked)
2501
+ }}
2502
+ />
2503
+ <span className='edit-label'>Display in Data Table</span>
2504
+ </label>
2505
+ </li>
2506
+ {/* disable for now */}
2507
+ {/*
2508
+ <li>
2509
+ <label className='checkbox'>
2510
+ <input
2511
+ type='checkbox'
2512
+ checked={config.columns[val].tooltip}
2513
+ onChange={event => {
2514
+ editColumn(val, 'tooltip', event.target.checked)
2515
+ }}
2516
+ />
2517
+ <span className='edit-label'>Display in Tooltips</span>
2518
+ </label>
2519
+ </li>
2520
+ */}
2521
+ </ul>
2522
+ </fieldset>
2523
+ ))}
2524
+ <button
2525
+ className={'btn full-width'}
2526
+ onClick={event => {
2527
+ event.preventDefault()
2528
+ addAdditionalColumn(additionalColumns.length + 1)
2529
+ }}
2530
+ >
2531
+ Add Column
2532
+ </button>
2533
+ </fieldset>
1799
2534
  )}
1800
-
1801
- {config.visualizationType === 'Pie' && (
1802
- <>
1803
- <CheckBox
1804
- value={config.exclusions.active}
1805
- section='exclusions'
1806
- fieldName='active'
1807
- label={'Exclude one or more values'}
1808
- updateField={updateField}
1809
- tooltip={
2535
+ {'category' === config.legend.type && (
2536
+ <fieldset className='primary-fieldset edit-block'>
2537
+ <label>
2538
+ <span className='edit-label'>
2539
+ Additional Category
1810
2540
  <Tooltip style={{ textTransform: 'none' }}>
1811
2541
  <Tooltip.Target>
1812
2542
  <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1813
2543
  </Tooltip.Target>
1814
2544
  <Tooltip.Content>
1815
- <p>When this option is checked, you can select values for exclusion from the pie segments.</p>
2545
+ <p>You can provide additional categories to ensure they appear in the legend</p>
1816
2546
  </Tooltip.Content>
1817
2547
  </Tooltip>
1818
- }
1819
- />
1820
- {config.exclusions.active && (
1821
- <>
1822
- {config.exclusions.keys.length > 0 && (
1823
- <>
1824
- <fieldset>
1825
- <legend className='edit-label'>Excluded Keys</legend>
1826
- </fieldset>
1827
- <ExclusionsList />
1828
- </>
1829
- )}
1830
-
1831
- <Select
1832
- fieldName='visualizationType'
1833
- label='Add Exclusion'
1834
- initial='Select'
1835
- onChange={e => {
1836
- if (e.target.value !== '' && e.target.value !== 'Select') {
1837
- addNewExclusion(e.target.value)
1838
- }
1839
- e.target.value = ''
1840
- }}
1841
- options={getDataValues(config.xAxis.dataKey, true)}
1842
- />
1843
- </>
1844
- )}
1845
- </>
2548
+ </span>
2549
+ </label>
2550
+ {config.legend.additionalCategories &&
2551
+ config.legend.additionalCategories.map((val, i) => (
2552
+ <fieldset className='edit-block' key={val}>
2553
+ <button
2554
+ className='remove-column'
2555
+ onClick={event => {
2556
+ event.preventDefault()
2557
+ const updatedAdditionaCategories = [...config.legend.additionalCategories]
2558
+ updatedAdditionaCategories.splice(i, 1)
2559
+ updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2560
+ }}
2561
+ >
2562
+ Remove
2563
+ </button>
2564
+ <label>
2565
+ <span className='edit-label column-heading'>Category</span>
2566
+ <TextField
2567
+ value={val}
2568
+ section='legend'
2569
+ subsection={null}
2570
+ fieldName='additionalCategories'
2571
+ updateField={(section, subsection, fieldName, value) => {
2572
+ const updatedAdditionaCategories = [...config.legend.additionalCategories]
2573
+ updatedAdditionaCategories[i] = value
2574
+ updateField(section, subsection, fieldName, updatedAdditionaCategories)
2575
+ }}
2576
+ />
2577
+ </label>
2578
+ </fieldset>
2579
+ ))}
2580
+ <button
2581
+ className={'btn full-width'}
2582
+ onClick={event => {
2583
+ event.preventDefault()
2584
+ const updatedAdditionaCategories = [...(config.legend.additionalCategories || [])]
2585
+ updatedAdditionaCategories.push('')
2586
+ updateField('legend', null, 'additionalCategories', updatedAdditionaCategories)
2587
+ }}
2588
+ >
2589
+ Add Category
2590
+ </button>
2591
+ </fieldset>
1846
2592
  )}
1847
2593
  </AccordionItemPanel>
1848
2594
  </AccordionItem>
1849
-
1850
- {config.visualizationType !== 'Pie' && config.visualizationType !== 'Paired Bar' && (
1851
- <AccordionItem>
1852
- <AccordionItemHeading>
1853
- <AccordionItemButton>Regions</AccordionItemButton>
1854
- </AccordionItemHeading>
1855
- <AccordionItemPanel>
1856
- <Regions config={config} updateConfig={updateConfig} />
1857
- </AccordionItemPanel>
1858
- </AccordionItem>
1859
- )}
1860
-
1861
- {visHasLegend() && (
1862
- <AccordionItem>
1863
- <AccordionItemHeading>
1864
- <AccordionItemButton>Legend</AccordionItemButton>
1865
- </AccordionItemHeading>
1866
- <AccordionItemPanel>
1867
- <CheckBox value={config.legend.reverseLabelOrder} section='legend' fieldName='reverseLabelOrder' label='Reverse Labels' updateField={updateField} />
1868
- {/* <fieldset className="checkbox-group">
2595
+ )}
2596
+ {/* End Columns */}
2597
+ {visHasLegend() && (
2598
+ <AccordionItem>
2599
+ <AccordionItemHeading>
2600
+ <AccordionItemButton>Legend</AccordionItemButton>
2601
+ </AccordionItemHeading>
2602
+ <AccordionItemPanel>
2603
+ <CheckBox value={config.legend.reverseLabelOrder} section='legend' fieldName='reverseLabelOrder' label='Reverse Labels' updateField={updateField} />
2604
+ {/* <fieldset className="checkbox-group">
1869
2605
  <CheckBox value={config.legend.dynamicLegend} section="legend" fieldName="dynamicLegend" label="Dynamic Legend" updateField={updateField}/>
1870
2606
  {config.legend.dynamicLegend && (
1871
2607
  <>
@@ -1876,54 +2612,53 @@ const EditorPanel = () => {
1876
2612
  </>
1877
2613
  )}
1878
2614
  </fieldset> */}
1879
- <CheckBox
1880
- value={config.legend.hide ? true : false}
1881
- section='legend'
1882
- fieldName='hide'
1883
- label='Hide Legend'
1884
- updateField={updateField}
1885
- tooltip={
1886
- <Tooltip style={{ textTransform: 'none' }}>
1887
- <Tooltip.Target>
1888
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
1889
- </Tooltip.Target>
1890
- <Tooltip.Content>
1891
- <p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
1892
- </Tooltip.Content>
1893
- </Tooltip>
1894
- }
1895
- />
2615
+ <CheckBox
2616
+ value={config.legend.hide ? true : false}
2617
+ section='legend'
2618
+ fieldName='hide'
2619
+ label='Hide Legend'
2620
+ updateField={updateField}
2621
+ tooltip={
2622
+ <Tooltip style={{ textTransform: 'none' }}>
2623
+ <Tooltip.Target>
2624
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
2625
+ </Tooltip.Target>
2626
+ <Tooltip.Content>
2627
+ <p>With a single-series chart, consider hiding the legend to reduce visual clutter.</p>
2628
+ </Tooltip.Content>
2629
+ </Tooltip>
2630
+ }
2631
+ />
1896
2632
 
1897
- {/* {config.visualizationType === 'Box Plot' &&
2633
+ {/* {config.visualizationType === 'Box Plot' &&
1898
2634
  <>
1899
2635
  <CheckBox value={config.boxplot.legend.displayHowToReadText} fieldName='displayHowToReadText' section='boxplot' subsection='legend' label='Display How To Read Text' updateField={updateField} />
1900
2636
  <TextField type='textarea' value={config.boxplot.legend.howToReadText} updateField={updateField} fieldName='howToReadText' section='boxplot' subsection='legend' label='How to read text' />
1901
2637
  </>
1902
2638
  } */}
1903
2639
 
1904
- {config.visualizationType !== 'Box Plot' && <CheckBox value={config.legend.showLegendValuesTooltip ? true : false} section='legend' fieldName='showLegendValuesTooltip' label='Show Legend Values in Tooltip' updateField={updateField} />}
1905
-
1906
- {config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1 && (
1907
- <Select value={config.legend.colorCode} section='legend' fieldName='colorCode' label='Color code by category' initial='Select' updateField={updateField} options={getDataValueOptions(data)} />
1908
- )}
1909
- <Select value={config.legend.behavior} section='legend' fieldName='behavior' label='Legend Behavior (When clicked)' updateField={updateField} options={['highlight', 'isolate']} />
1910
- <TextField value={config.legend.label} section='legend' fieldName='label' label='Title' updateField={updateField} />
1911
- <Select value={config.legend.position} section='legend' fieldName='position' label='Position' updateField={updateField} options={['right', 'left', 'bottom']} />
1912
- {config.legend.position === 'bottom' && <CheckBox value={config.legend.singleRow} section='legend' fieldName='singleRow' label='Single Row Legend' updateField={updateField} />}
1913
- <TextField type='textarea' value={config.legend.description} updateField={updateField} section='legend' fieldName='description' label='Legend Description' />
1914
- </AccordionItemPanel>
1915
- </AccordionItem>
1916
- )}
2640
+ {config.visualizationType !== 'Box Plot' && <CheckBox value={config.legend.showLegendValuesTooltip ? true : false} section='legend' fieldName='showLegendValuesTooltip' label='Show Legend Values in Tooltip' updateField={updateField} />}
1917
2641
 
1918
- <AccordionItem>
1919
- <AccordionItemHeading>
1920
- <AccordionItemButton>Filters</AccordionItemButton>
1921
- </AccordionItemHeading>
1922
- <AccordionItemPanel>
1923
- {config.filters && (
1924
- <>
1925
- {/* prettier-ignore */}
1926
- <Select
2642
+ {config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1 && (
2643
+ <Select value={config.legend.colorCode} section='legend' fieldName='colorCode' label='Color code by category' initial='Select' updateField={updateField} options={getDataValueOptions(data)} />
2644
+ )}
2645
+ <Select value={config.legend.behavior} section='legend' fieldName='behavior' label='Legend Behavior (When clicked)' updateField={updateField} options={['highlight', 'isolate']} />
2646
+ <TextField value={config.legend.label} section='legend' fieldName='label' label='Title' updateField={updateField} />
2647
+ <Select value={config.legend.position} section='legend' fieldName='position' label='Position' updateField={updateField} options={['right', 'left', 'bottom']} />
2648
+ {config.legend.position === 'bottom' && <CheckBox value={config.legend.singleRow} section='legend' fieldName='singleRow' label='Single Row Legend' updateField={updateField} />}
2649
+ <TextField type='textarea' value={config.legend.description} updateField={updateField} section='legend' fieldName='description' label='Legend Description' />
2650
+ </AccordionItemPanel>
2651
+ </AccordionItem>
2652
+ )}
2653
+ <AccordionItem>
2654
+ <AccordionItemHeading>
2655
+ <AccordionItemButton>Filters</AccordionItemButton>
2656
+ </AccordionItemHeading>
2657
+ <AccordionItemPanel>
2658
+ {config.filters && (
2659
+ <>
2660
+ {/* prettier-ignore */}
2661
+ <Select
1927
2662
  value={config.filterBehavior}
1928
2663
  fieldName='filterBehavior'
1929
2664
  label='Filter Behavior'
@@ -1940,14 +2675,17 @@ const EditorPanel = () => {
1940
2675
  </Tooltip>
1941
2676
  }
1942
2677
  />
1943
- <br />
1944
- </>
1945
- )}
1946
- {config.filters && (
1947
- <ul className='filters-list'>
1948
- {/* Whether filters should apply onChange or Apply Button */}
2678
+ <br />
2679
+ </>
2680
+ )}
2681
+ {config.filters && (
2682
+ <ul className='filters-list'>
2683
+ {/* Whether filters should apply onChange or Apply Button */}
2684
+
2685
+ {config.filters.map((filter, index) => {
2686
+ if (filter.type === 'url') return <></>
1949
2687
 
1950
- {config.filters.map((filter, index) => (
2688
+ return (
1951
2689
  <fieldset className='edit-block' key={index}>
1952
2690
  <button
1953
2691
  type='button'
@@ -1975,8 +2713,18 @@ const EditorPanel = () => {
1975
2713
  </select>
1976
2714
  </label>
1977
2715
 
1978
- {/* COMING SOON: 4.23.5 FILTER STYLES */}
1979
- {/* <label>
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>
2726
+
2727
+ <label>
1980
2728
  <span className='edit-label column-heading'>Filter Style</span>
1981
2729
 
1982
2730
  <select
@@ -1989,7 +2737,7 @@ const EditorPanel = () => {
1989
2737
  return <option value={item}>{item}</option>
1990
2738
  })}
1991
2739
  </select>
1992
- </label> */}
2740
+ </label>
1993
2741
  <label>
1994
2742
  <span className='edit-label column-heading'>Label</span>
1995
2743
  <input
@@ -2039,230 +2787,238 @@ const EditorPanel = () => {
2039
2787
  )}
2040
2788
  </label>
2041
2789
  </fieldset>
2042
- ))}
2043
- </ul>
2044
- )}
2045
- {!config.filters && <p style={{ textAlign: 'center' }}>There are currently no filters.</p>}
2046
- <button type='button' onClick={addNewFilter} className='btn full-width'>
2047
- Add Filter
2048
- </button>
2049
- </AccordionItemPanel>
2050
- </AccordionItem>
2051
-
2052
- <AccordionItem>
2053
- <AccordionItemHeading>
2054
- <AccordionItemButton>Visual</AccordionItemButton>
2055
- </AccordionItemHeading>
2056
- <AccordionItemPanel>
2057
- {config.isLollipopChart && (
2058
- <>
2059
- <fieldset className='header'>
2060
- <legend className='edit-label'>Lollipop Shape</legend>
2061
- <div
2062
- onChange={e => {
2063
- setLollipopShape(e.target.value)
2064
- }}
2065
- >
2066
- <label className='radio-label'>
2067
- <input type='radio' name='lollipopShape' value='circle' checked={config.lollipopShape === 'circle'} />
2068
- Circle
2069
- </label>
2070
- <label className='radio-label'>
2071
- <input type='radio' name='lollipopShape' value='square' checked={config.lollipopShape === 'square'} />
2072
- Square
2073
- </label>
2074
- </div>
2075
- </fieldset>
2076
- <Select value={config.lollipopColorStyle ? config.lollipopColorStyle : 'two-tone'} fieldName='lollipopColorStyle' label='Lollipop Color Style' updateField={updateField} options={['regular', 'two-tone']} />
2077
- <Select value={config.lollipopSize ? config.lollipopSize : 'small'} fieldName='lollipopSize' label='Lollipop Size' updateField={updateField} options={['small', 'medium', 'large']} />
2078
- </>
2079
- )}
2080
-
2081
- {config.visualizationType === 'Box Plot' && (
2082
- <fieldset className='fieldset fieldset--boxplot'>
2083
- <legend className=''>Box Plot Settings</legend>
2084
- <Select value={config.boxplot.borders} fieldName='borders' section='boxplot' label='Box Plot Borders' updateField={updateField} options={['true', 'false']} />
2085
- <CheckBox value={config.boxplot.plotOutlierValues} fieldName='plotOutlierValues' section='boxplot' label='Plot Outliers' updateField={updateField} />
2086
- <CheckBox value={config.boxplot.plotNonOutlierValues} fieldName='plotNonOutlierValues' section='boxplot' label='Plot non-outlier values' updateField={updateField} />
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>
2800
+ <AccordionItem>
2801
+ <AccordionItemHeading>
2802
+ <AccordionItemButton>Visual</AccordionItemButton>
2803
+ </AccordionItemHeading>
2804
+ <AccordionItemPanel>
2805
+ {config.isLollipopChart && (
2806
+ <>
2807
+ <fieldset className='header'>
2808
+ <legend className='edit-label'>Lollipop Shape</legend>
2809
+ <div
2810
+ onChange={e => {
2811
+ setLollipopShape(e.target.value)
2812
+ }}
2813
+ >
2814
+ <label className='radio-label'>
2815
+ <input type='radio' name='lollipopShape' value='circle' checked={config.lollipopShape === 'circle'} />
2816
+ Circle
2817
+ </label>
2818
+ <label className='radio-label'>
2819
+ <input type='radio' name='lollipopShape' value='square' checked={config.lollipopShape === 'square'} />
2820
+ Square
2821
+ </label>
2822
+ </div>
2087
2823
  </fieldset>
2088
- )}
2089
-
2090
- <Select value={config.fontSize} fieldName='fontSize' label='Font Size' updateField={updateField} options={['small', 'medium', 'large']} />
2091
- {visHasBarBorders() && <Select value={config.barHasBorder} fieldName='barHasBorder' label='Bar Borders' updateField={updateField} options={['true', 'false']} />}
2092
- {visCanAnimate() && <CheckBox value={config.animate} fieldName='animate' label='Animate Visualization' updateField={updateField} />}
2093
-
2094
- {/*<CheckBox value={config.animateReplay} fieldName="animateReplay" label="Replay Animation When Filters Are Changed" updateField={updateField} />*/}
2095
-
2096
- {((config.series?.some(series => series.type === 'Line') && config.visualizationType === 'Combo') || config.visualizationType === 'Line' || config.visualizationType === 'Spark Line') && (
2097
- <Select value={config.lineDatapointStyle} fieldName='lineDatapointStyle' label='Line Datapoint Style' updateField={updateField} options={['hidden', 'hover', 'always show']} />
2098
- )}
2099
-
2100
- {/* eslint-disable */}
2101
- <label className='header'>
2102
- <span className='edit-label'>Header Theme</span>
2824
+ <Select value={config.lollipopColorStyle ? config.lollipopColorStyle : 'two-tone'} fieldName='lollipopColorStyle' label='Lollipop Color Style' updateField={updateField} options={['regular', 'two-tone']} />
2825
+ <Select value={config.lollipopSize ? config.lollipopSize : 'small'} fieldName='lollipopSize' label='Lollipop Size' updateField={updateField} options={['small', 'medium', 'large']} />
2826
+ </>
2827
+ )}
2828
+
2829
+ {config.visualizationType === 'Box Plot' && (
2830
+ <fieldset className='fieldset fieldset--boxplot'>
2831
+ <legend className=''>Box Plot Settings</legend>
2832
+ <Select value={config.boxplot.borders} fieldName='borders' section='boxplot' label='Box Plot Borders' updateField={updateField} options={['true', 'false']} />
2833
+ <CheckBox value={config.boxplot.plotOutlierValues} fieldName='plotOutlierValues' section='boxplot' label='Plot Outliers' updateField={updateField} />
2834
+ <CheckBox value={config.boxplot.plotNonOutlierValues} fieldName='plotNonOutlierValues' section='boxplot' label='Plot non-outlier values' updateField={updateField} />
2835
+ </fieldset>
2836
+ )}
2837
+
2838
+ <Select value={config.fontSize} fieldName='fontSize' label='Font Size' updateField={updateField} options={['small', 'medium', 'large']} />
2839
+ {visHasBarBorders() && <Select value={config.barHasBorder} fieldName='barHasBorder' label='Bar Borders' updateField={updateField} options={['true', 'false']} />}
2840
+ {visCanAnimate() && <CheckBox value={config.animate} fieldName='animate' label='Animate Visualization' updateField={updateField} />}
2841
+
2842
+ {/*<CheckBox value={config.animateReplay} fieldName="animateReplay" label="Replay Animation When Filters Are Changed" updateField={updateField} />*/}
2843
+
2844
+ {((config.series?.some(series => series.type === 'Line') && config.visualizationType === 'Combo') || config.visualizationType === 'Line') && (
2845
+ <Select value={config.lineDatapointStyle} fieldName='lineDatapointStyle' label='Line Datapoint Style' updateField={updateField} options={['hidden', 'hover', 'always show']} />
2846
+ )}
2847
+
2848
+ {/* eslint-disable */}
2849
+ <label className='header'>
2850
+ <span className='edit-label'>Header Theme</span>
2851
+ <ul className='color-palette'>
2852
+ {headerColors.map(palette => (
2853
+ <button
2854
+ title={palette}
2855
+ key={palette}
2856
+ onClick={e => {
2857
+ e.preventDefault()
2858
+ updateConfig({ ...config, theme: palette })
2859
+ }}
2860
+ className={config.theme === palette ? 'selected ' + palette : palette}
2861
+ ></button>
2862
+ ))}
2863
+ </ul>
2864
+ </label>
2865
+ <label>
2866
+ <span className='edit-label'>Chart Color Palette</span>
2867
+ </label>
2868
+ {/* eslint-enable */}
2869
+ {config.visualizationType !== 'Paired Bar' && config.visualizationType !== 'Deviation Bar' && (
2870
+ <>
2871
+ <InputToggle fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={config.isPaletteReversed} />
2872
+ <span>Sequential</span>
2103
2873
  <ul className='color-palette'>
2104
- {headerColors.map(palette => (
2105
- <button
2106
- title={palette}
2107
- key={palette}
2108
- onClick={e => {
2109
- e.preventDefault()
2110
- updateConfig({ ...config, theme: palette })
2111
- }}
2112
- className={config.theme === palette ? 'selected ' + palette : palette}
2113
- ></button>
2114
- ))}
2115
- </ul>
2116
- </label>
2117
- <label>
2118
- <span className='edit-label'>Chart Color Palette</span>
2119
- </label>
2120
- {/* eslint-enable */}
2121
- {config.visualizationType !== 'Paired Bar' && config.visualizationType !== 'Deviation Bar' && (
2122
- <>
2123
- <InputToggle fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={config.isPaletteReversed} />
2124
- <span>Sequential</span>
2125
- <ul className='color-palette'>
2126
- {sequential.map(palette => {
2127
- const colorOne = {
2128
- backgroundColor: colorPalettes[palette][2]
2129
- }
2130
-
2131
- const colorTwo = {
2132
- backgroundColor: colorPalettes[palette][3]
2133
- }
2134
-
2135
- const colorThree = {
2136
- backgroundColor: colorPalettes[palette][5]
2137
- }
2874
+ {sequential.map(palette => {
2875
+ const colorOne = {
2876
+ backgroundColor: colorPalettes[palette][2]
2877
+ }
2138
2878
 
2139
- return (
2140
- <button
2141
- title={palette}
2142
- key={palette}
2143
- onClick={e => {
2144
- e.preventDefault()
2145
- updateConfig({ ...config, palette })
2146
- }}
2147
- className={config.palette === palette ? 'selected' : ''}
2148
- >
2149
- <span style={colorOne}></span>
2150
- <span style={colorTwo}></span>
2151
- <span style={colorThree}></span>
2152
- </button>
2153
- )
2154
- })}
2155
- </ul>
2156
- <span>Non-Sequential</span>
2157
- <ul className='color-palette'>
2158
- {nonSequential.map(palette => {
2159
- const colorOne = {
2160
- backgroundColor: colorPalettes[palette][2]
2161
- }
2879
+ const colorTwo = {
2880
+ backgroundColor: colorPalettes[palette][3]
2881
+ }
2162
2882
 
2163
- const colorTwo = {
2164
- backgroundColor: colorPalettes[palette][4]
2165
- }
2883
+ const colorThree = {
2884
+ backgroundColor: colorPalettes[palette][5]
2885
+ }
2166
2886
 
2167
- const colorThree = {
2168
- backgroundColor: colorPalettes[palette][6]
2169
- }
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
+ }
2170
2910
 
2171
- return (
2172
- <button
2173
- title={palette}
2174
- key={palette}
2175
- onClick={e => {
2176
- e.preventDefault()
2177
- updateConfig({ ...config, palette })
2178
- }}
2179
- className={config.palette === palette ? 'selected' : ''}
2180
- >
2181
- <span style={colorOne}></span>
2182
- <span style={colorTwo}></span>
2183
- <span style={colorThree}></span>
2184
- </button>
2185
- )
2186
- })}
2187
- </ul>
2188
- </>
2189
- )}
2190
- {(config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') && (
2191
- <>
2192
- <InputToggle section='twoColor' fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={config.twoColor.isPaletteReversed} />
2193
- <ul className='color-palette'>
2194
- {twoColorPalettes.map(palette => {
2195
- const colorOne = {
2196
- backgroundColor: twoColorPalette[palette][0]
2197
- }
2911
+ const colorTwo = {
2912
+ backgroundColor: colorPalettes[palette][4]
2913
+ }
2198
2914
 
2199
- const colorTwo = {
2200
- backgroundColor: twoColorPalette[palette][1]
2201
- }
2915
+ const colorThree = {
2916
+ backgroundColor: colorPalettes[palette][6]
2917
+ }
2202
2918
 
2203
- return (
2204
- <button
2205
- title={palette}
2206
- key={palette}
2207
- onClick={e => {
2208
- e.preventDefault()
2209
- updateConfig({ ...config, twoColor: { ...config.twoColor, palette } })
2210
- }}
2211
- className={config.twoColor.palette === palette ? 'selected' : ''}
2212
- >
2213
- <span className='two-color' style={colorOne}></span>
2214
- <span className='two-color' style={colorTwo}></span>
2215
- </button>
2216
- )
2217
- })}
2218
- </ul>
2219
- </>
2220
- )}
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>
2936
+ </>
2937
+ )}
2938
+ {(config.visualizationType === 'Paired Bar' || config.visualizationType === 'Deviation Bar') && (
2939
+ <>
2940
+ <InputToggle section='twoColor' fieldName='isPaletteReversed' size='small' label='Use selected palette in reverse order' updateField={updateField} value={config.twoColor.isPaletteReversed} />
2941
+ <ul className='color-palette'>
2942
+ {twoColorPalettes.map(palette => {
2943
+ const colorOne = {
2944
+ backgroundColor: twoColorPalette[palette][0]
2945
+ }
2221
2946
 
2222
- {visHasDataCutoff() && (
2223
- <>
2224
- <TextField
2225
- value={config.dataCutoff}
2226
- type='number'
2227
- fieldName='dataCutoff'
2228
- className='number-narrow'
2229
- label='Data Cutoff'
2230
- updateField={updateField}
2231
- tooltip={
2232
- <Tooltip style={{ textTransform: 'none' }}>
2233
- <Tooltip.Target>
2234
- <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2235
- </Tooltip.Target>
2236
- <Tooltip.Content>
2237
- <p>Any value below the cut-off value is included in a special "less than" category. This option supports special conditions like suppressed data.</p>
2238
- </Tooltip.Content>
2239
- </Tooltip>
2947
+ const colorTwo = {
2948
+ backgroundColor: twoColorPalette[palette][1]
2240
2949
  }
2241
- />
2242
- </>
2243
- )}
2244
- {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' />}
2245
- {((config.visualizationType === 'Bar' && config.orientation !== 'horizontal') || config.visualizationType === 'Combo') && <TextField value={config.barThickness} type='number' fieldName='barThickness' label='Bar Thickness' updateField={updateField} />}
2246
- {(config.orientation === 'horizontal' || config.visualizationType === 'Paired Bar') && <TextField type='number' value={config.barSpace || '15'} fieldName='barSpace' label='Bar Space' updateField={updateField} min='0' />}
2247
- {(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} />}
2248
-
2249
- {config.visualizationType === 'Spark Line' && (
2250
- <div className='cove-accordion__panel-section checkbox-group'>
2251
- <CheckBox value={config.visual?.border} section='visual' fieldName='border' label='Display Border' updateField={updateField} />
2252
- <CheckBox value={config.visual?.borderColorTheme} section='visual' fieldName='borderColorTheme' label='Use Border Color Theme' updateField={updateField} />
2253
- <CheckBox value={config.visual?.accent} section='visual' fieldName='accent' label='Use Accent Style' updateField={updateField} />
2254
- <CheckBox value={config.visual?.background} section='visual' fieldName='background' label='Use Theme Background Color' updateField={updateField} />
2255
- <CheckBox value={config.visual?.hideBackgroundColor} section='visual' fieldName='hideBackgroundColor' label='Hide Background Color' updateField={updateField} />
2256
- </div>
2257
- )}
2258
2950
 
2259
- {(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && <CheckBox value={config.showLineSeriesLabels} fieldName='showLineSeriesLabels' label='Append Series Name to End of Line Charts' updateField={updateField} />}
2260
- {(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && config.showLineSeriesLabels && (
2261
- <CheckBox value={config.colorMatchLineSeriesLabels} fieldName='colorMatchLineSeriesLabels' label='Match Series Color to Name at End of Line Charts' updateField={updateField} />
2262
- )}
2263
- </AccordionItemPanel>
2264
- </AccordionItem>
2951
+ return (
2952
+ <button
2953
+ title={palette}
2954
+ key={palette}
2955
+ onClick={e => {
2956
+ e.preventDefault()
2957
+ updateConfig({ ...config, twoColor: { ...config.twoColor, palette } })
2958
+ }}
2959
+ className={config.twoColor.palette === palette ? 'selected' : ''}
2960
+ >
2961
+ <span className='two-color' style={colorOne}></span>
2962
+ <span className='two-color' style={colorTwo}></span>
2963
+ </button>
2964
+ )
2965
+ })}
2966
+ </ul>
2967
+ </>
2968
+ )}
2265
2969
 
2970
+ {visHasDataCutoff() && (
2971
+ <>
2972
+ <TextField
2973
+ value={config.dataCutoff}
2974
+ type='number'
2975
+ fieldName='dataCutoff'
2976
+ className='number-narrow'
2977
+ label='Data Cutoff'
2978
+ updateField={updateField}
2979
+ tooltip={
2980
+ <Tooltip style={{ textTransform: 'none' }}>
2981
+ <Tooltip.Target>
2982
+ <Icon display='question' style={{ marginLeft: '0.5rem' }} />
2983
+ </Tooltip.Target>
2984
+ <Tooltip.Content>
2985
+ <p>Any value below the cut-off value is included in a special "less than" category. This option supports special conditions like suppressed data.</p>
2986
+ </Tooltip.Content>
2987
+ </Tooltip>
2988
+ }
2989
+ />
2990
+ </>
2991
+ )}
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' />}
2993
+ {((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' />}
2995
+ {(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
+
2997
+ {config.visualizationType === 'Spark Line' && (
2998
+ <div className='cove-accordion__panel-section checkbox-group'>
2999
+ <CheckBox value={config.visual?.border} section='visual' fieldName='border' label='Display Border' updateField={updateField} />
3000
+ <CheckBox value={config.visual?.borderColorTheme} section='visual' fieldName='borderColorTheme' label='Use Border Color Theme' updateField={updateField} />
3001
+ <CheckBox value={config.visual?.accent} section='visual' fieldName='accent' label='Use Accent Style' updateField={updateField} />
3002
+ <CheckBox value={config.visual?.background} section='visual' fieldName='background' label='Use Theme Background Color' updateField={updateField} />
3003
+ <CheckBox value={config.visual?.hideBackgroundColor} section='visual' fieldName='hideBackgroundColor' label='Hide Background Color' updateField={updateField} />
3004
+ </div>
3005
+ )}
3006
+
3007
+ {(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && <CheckBox value={config.showLineSeriesLabels} fieldName='showLineSeriesLabels' label='Append Series Name to End of Line Charts' updateField={updateField} />}
3008
+ {(config.visualizationType === 'Line' || config.visualizationType === 'Combo') && config.showLineSeriesLabels && (
3009
+ <CheckBox value={config.colorMatchLineSeriesLabels} fieldName='colorMatchLineSeriesLabels' label='Match Series Color to Name at End of Line Charts' updateField={updateField} />
3010
+ )}
3011
+
3012
+ {visSupportsTooltipLines() && (
3013
+ <>
3014
+ <CheckBox value={config.visual.verticalHoverLine} fieldName='verticalHoverLine' section='visual' label='Vertical Hover Line' updateField={updateField} />
3015
+ <CheckBox value={config.visual.horizontalHoverLine} fieldName='horizontalHoverLine' section='visual' label='Horizontal Hover Line' updateField={updateField} />
3016
+ </>
3017
+ )}
3018
+ </AccordionItemPanel>
3019
+ </AccordionItem>
3020
+ {/* Spark Line has no data table */}
3021
+ {config.visualizationType !== 'Spark Line' && (
2266
3022
  <AccordionItem>
2267
3023
  <AccordionItemHeading>
2268
3024
  <AccordionItemButton>Data Table</AccordionItemButton>
@@ -2305,6 +3061,27 @@ const EditorPanel = () => {
2305
3061
  </Tooltip>
2306
3062
  }
2307
3063
  />
3064
+ {config.visualizationType !== 'Box Plot' && (
3065
+ <CheckBox
3066
+ value={config.table.showVertical}
3067
+ section='table'
3068
+ fieldName='showVertical'
3069
+ label='Show Vertical Data'
3070
+ updateField={updateField}
3071
+ className='column-heading'
3072
+ tooltip={
3073
+ <Tooltip style={{ textTransform: 'none' }}>
3074
+ <Tooltip.Target>
3075
+ <Icon display='question' style={{ marginLeft: '0.5rem', display: 'inline-block', whiteSpace: 'nowrap' }} />
3076
+ </Tooltip.Target>
3077
+ <Tooltip.Content>
3078
+ <p>This will draw the data table with vertical data instead of horizontal.</p>
3079
+ </Tooltip.Content>
3080
+ </Tooltip>
3081
+ }
3082
+ />
3083
+ )}
3084
+ <TextField value={config.table.indexLabel} section='table' fieldName='indexLabel' label='Index Column Header' updateField={updateField} />
2308
3085
  <TextField
2309
3086
  value={config.table.caption}
2310
3087
  updateField={updateField}
@@ -2332,11 +3109,10 @@ const EditorPanel = () => {
2332
3109
  <CheckBox value={config.table.download} section='table' fieldName='download' label='Show Download CSV Link' updateField={updateField} />
2333
3110
  {/* <CheckBox value={config.table.showDownloadImgButton} section='table' fieldName='showDownloadImgButton' label='Display Image Button' updateField={updateField} /> */}
2334
3111
  {/* <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
3112
  </AccordionItemPanel>
2337
3113
  </AccordionItem>
2338
- </Accordion>
2339
- </form>
3114
+ )}
3115
+ </Accordion>
2340
3116
  {config.type !== 'Spark Line' && <AdvancedEditor loadConfig={updateConfig} state={config} convertStateToConfig={convertStateToConfig} />}
2341
3117
  </section>
2342
3118
  </section>