@cdc/chart 4.23.3 → 4.23.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/dist/cdcchart.js +52543 -50830
  2. package/examples/feature/__data__/area-chart.json +56 -0
  3. package/examples/{planet-example-data.json → feature/__data__/planet-example-data.json} +3 -8
  4. package/examples/feature/__data__/planet-logaritmic-data.json +56 -0
  5. package/examples/feature/area/area-chart-category.json +240 -0
  6. package/examples/{area-chart.json → feature/area/area-chart-date.json} +70 -13
  7. package/examples/feature/bar/example-bar-chart.json +558 -0
  8. package/examples/{horizontal-chart-max-increase.json → feature/bar/horizontal-chart-max-increase.json} +10 -4
  9. package/examples/{horizontal-chart.json → feature/bar/horizontal-chart.json} +10 -4
  10. package/examples/{horizontal-stacked-bar-chart.json → feature/bar/horizontal-stacked-bar-chart.json} +7 -3
  11. package/examples/{planet-chart-horizontal-example-config.json → feature/bar/planet-chart-horizontal-example-config.json} +8 -3
  12. package/examples/feature/bar/planet-chart-logaritmic-config.json +170 -0
  13. package/examples/{planet-example-config.json → feature/bar/planet-example-config.json} +2 -2
  14. package/examples/{box-plot.json → feature/boxplot/boxplot.json} +7 -7
  15. package/examples/feature/boxplot/testing.csv +38 -0
  16. package/examples/feature/boxplot/valid-boxplot.csv +17 -0
  17. package/examples/feature/combo/combochart-categories_are_numbers .json +18 -0
  18. package/examples/{planet-combo-example-config.json → feature/combo/planet-combo-example-config.json} +1 -1
  19. package/examples/{planet-deviation-config.json → feature/deviation/planet-deviation-config.json} +2 -2
  20. package/examples/{planet-deviation-data.json → feature/deviation/planet-deviation-data.json} +9 -9
  21. package/examples/feature/filters/filter-testing.json +212 -0
  22. package/examples/feature/forecasting/case_date_example.csv +130 -0
  23. package/examples/feature/forecasting/effective_reproduction.json +202 -0
  24. package/examples/feature/forecasting/r_data.csv +130 -0
  25. package/examples/feature/forecasting/random_data.csv +366 -0
  26. package/examples/feature/line/line-chart.json +124 -0
  27. package/examples/{paired-bar-example.json → feature/paired-bar/paired-bar-example.json} +10 -4
  28. package/examples/{planet-pie-example-config.json → feature/pie/planet-pie-example-config.json} +2 -2
  29. package/examples/{scatterplot.json → feature/scatterplot/scatterplot.json} +1 -1
  30. package/examples/feature/test-highlight/test-highlight-2.json +789 -0
  31. package/examples/feature/test-highlight/test-highlight-vertical.json +561 -0
  32. package/examples/feature/test-highlight/test-highlight.json +100 -0
  33. package/examples/{case-rate-example-config.json → feature/tests-case-rate/case-rate-example-config.json} +2 -2
  34. package/examples/{covid-confidence-example-config.json → feature/tests-covid/covid-confidence-example-config.json} +8 -3
  35. package/examples/{covid-example-config.json → feature/tests-covid/covid-example-config.json} +7 -3
  36. package/examples/{cutoff-example-config.json → feature/tests-cutoff/cutoff-example-config.json} +7 -3
  37. package/examples/{date-exclusions-config.json → feature/tests-date-exclusions/date-exclusions-config.json} +2 -2
  38. package/examples/{example-bar-chart-nonnumeric.json → feature/tests-non-numerics/example-bar-chart-nonnumeric.json} +1 -1
  39. package/examples/{planet-pie-example-config-nonnumeric.json → feature/tests-non-numerics/planet-pie-example-config-nonnumeric.json} +2 -2
  40. package/examples/{sparkline-chart-nonnumeric.json → feature/tests-non-numerics/sparkline-chart-nonnumeric.json} +1 -1
  41. package/examples/{stacked-vertical-bar-example-nonnumerics.json → feature/tests-non-numerics/stacked-vertical-bar-example-nonnumerics.json} +1 -2
  42. package/examples/gallery/bar-chart-horizontal/horizontal-highlight.json +345 -0
  43. package/examples/gallery/bar-chart-vertical/combo-line-chart.json +145 -7
  44. package/examples/gallery/paired-bar/paired-bar-chart.json +1 -0
  45. package/index.html +73 -49
  46. package/package.json +2 -2
  47. package/src/CdcChart.jsx +405 -40
  48. package/src/components/AreaChart.jsx +122 -80
  49. package/src/components/BarChart.jsx +126 -49
  50. package/src/components/BoxPlot.jsx +28 -20
  51. package/src/components/DataTable.jsx +7 -6
  52. package/src/components/DeviationBar.jsx +34 -34
  53. package/src/components/EditorPanel.jsx +1332 -352
  54. package/src/components/Legend.jsx +40 -4
  55. package/src/components/LineChart.jsx +10 -23
  56. package/src/components/LinearChart.jsx +133 -286
  57. package/src/components/PairedBarChart.jsx +6 -6
  58. package/src/components/PieChart.jsx +2 -4
  59. package/src/components/SparkLine.jsx +6 -42
  60. package/src/data/initial-state.js +23 -4
  61. package/src/hooks/useHighlightedBars.js +154 -0
  62. package/src/hooks/useMinMax.js +92 -0
  63. package/src/hooks/useReduceData.js +31 -57
  64. package/src/hooks/useScales.js +202 -0
  65. package/src/index.jsx +2 -1
  66. package/src/scss/editor-panel.scss +15 -0
  67. package/src/scss/main.scss +8 -6
  68. package/examples/box-plot.csv +0 -5
  69. package/examples/dynamic-legends.json +0 -125
  70. package/examples/example-bar-chart.json +0 -36
  71. package/examples/line-chart.json +0 -34
  72. package/examples/temp-example-config.json +0 -64
  73. package/examples/temp-example-data.json +0 -130
  74. package/src/components/Filters.jsx +0 -126
  75. /package/examples/{age-adjusted-rates.json → feature/__data__/age-adjusted-rates.json} +0 -0
  76. /package/examples/{new-data.csv → feature/__data__/new-data.csv} +0 -0
  77. /package/examples/{planet-example-data-max-increase.json → feature/__data__/planet-example-data-max-increase.json} +0 -0
  78. /package/examples/{Barchart_with_negative.json → feature/bar/Barchart_with_negative.json} +0 -0
  79. /package/examples/{stacked-vertical-bar-example-negative.json → feature/bar/stacked-vertical-bar-example-negative.json} +0 -0
  80. /package/examples/{stacked-vertical-bar-example.json → feature/bar/stacked-vertical-bar-example.json} +0 -0
  81. /package/examples/{box-plot-data.json → feature/boxplot/box-plot-data.json} +0 -0
  82. /package/examples/{newdata.json → feature/boxplot/boxplot-data.json} +0 -0
  83. /package/examples/{line-chart-max-increase.json → feature/line/line-chart-max-increase.json} +0 -0
  84. /package/examples/{paired-bar-data.json → feature/paired-bar/paired-bar-data.json} +0 -0
  85. /package/examples/{paired-bar-formatted.json → feature/paired-bar/paired-bar-formatted.json} +0 -0
  86. /package/examples/{scatterplot-continuous.csv → feature/scatterplot/scatterplot-continuous.csv} +0 -0
  87. /package/examples/{example-sparkline.json → feature/sparkline/example-sparkline.json} +0 -0
  88. /package/examples/{big-small-test-bar.json → feature/tests-big-small/big-small-test-bar.json} +0 -0
  89. /package/examples/{big-small-test-line.json → feature/tests-big-small/big-small-test-line.json} +0 -0
  90. /package/examples/{big-small-test-negative.json → feature/tests-big-small/big-small-test-negative.json} +0 -0
  91. /package/examples/{case-rate-example-data.json → feature/tests-case-rate/case-rate-example-data.json} +0 -0
  92. /package/examples/{covid-example-data-confidence.json → feature/tests-covid/covid-example-data-confidence.json} +0 -0
  93. /package/examples/{covid-example-data.json → feature/tests-covid/covid-example-data.json} +0 -0
  94. /package/examples/{cutoff-example-data.json → feature/tests-cutoff/cutoff-example-data.json} +0 -0
  95. /package/examples/{date-exclusions-data.json → feature/tests-date-exclusions/date-exclusions-data.json} +0 -0
  96. /package/examples/{example-combo-bar-nonnumeric.json → feature/tests-non-numerics/example-combo-bar-nonnumeric.json} +0 -0
  97. /package/examples/{line-chart-nonnumeric.json → feature/tests-non-numerics/line-chart-nonnumeric.json} +0 -0
  98. /package/examples/{planet-example-data-nonnumeric.json → feature/tests-non-numerics/planet-example-data-nonnumeric.json} +0 -0
@@ -35,43 +35,7 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
35
35
  const isMaxValid = Number(enteredMaxValue) >= Number(maxValue)
36
36
  const isMinValid = Number(enteredMinValue) <= Number(minValue)
37
37
 
38
- // REMOVE bad data points from the data set
39
- // Examples: NA, N/A, "1,234", "anystring"
40
- // - if you dont call this on data into LineGroup below, for example
41
- // then entire data series are removed because of the defined statement
42
- // i.e. if a series has any bad data points the entire series wont plot
43
- const cleanData = (data, testing = false) => {
44
- let cleanedup = []
45
- if (testing) console.log('## Data to clean=', data)
46
- data.forEach(function (d, i) {
47
- let cleanedSeries = {}
48
- Object.keys(d).forEach(function (key) {
49
- if (key === 'Date') {
50
- // pass thru the dates
51
- cleanedSeries[key] = d[key]
52
- } else {
53
- // remove comma and dollar signs
54
- let tmp = d[key] !== null && d[key] !== '' ? d[key].replace(/[,$]/g, '') : ''
55
- if (testing) console.log('tmp no comma or $', tmp)
56
- if ((tmp !== '' && tmp !== null && !isNaN(tmp)) || (tmp !== '' && tmp !== null && /\d+\.?\d*/.test(tmp))) {
57
- cleanedSeries[key] = tmp
58
- } else {
59
- // return nothing to skip bad data point
60
- cleanedSeries[key] = '' // returning blank fixes broken chart draw
61
- }
62
- }
63
- })
64
- cleanedup.push(cleanedSeries)
65
- })
66
- if (testing) console.log('## cleanedData =', cleanedup)
67
- return cleanedup
68
- }
69
-
70
- // Just do this once up front otherwise we end up
71
- // calling clean several times on same set of data (TT)
72
- const cleanedData = cleanData(data, config.xAxis.dataKey)
73
-
74
- if (cleanedData) {
38
+ if (data) {
75
39
  let min = enteredMinValue && isMinValid ? enteredMinValue : minValue
76
40
  let max = enteredMaxValue && isMaxValid ? enteredMaxValue : Number.MIN_VALUE
77
41
 
@@ -86,7 +50,7 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
86
50
  max += paddingValue
87
51
  }
88
52
 
89
- let xAxisDataMapped = cleanedData.map(d => getXAxisData(d))
53
+ let xAxisDataMapped = data.map(d => getXAxisData(d))
90
54
 
91
55
  if (config.runtime.horizontal) {
92
56
  xScale = scaleLinear({
@@ -128,7 +92,7 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
128
92
  return (
129
93
  <ErrorBoundary component='SparkLine'>
130
94
  <svg role='img' aria-label={handleChartAriaLabels(config)} width={width} height={height} className={'sparkline'} tabIndex={0}>
131
- {config.runtime.lineSeriesKeys.length > 0
95
+ {config.runtime.lineSeriesKeys?.length > 0
132
96
  ? config.runtime.lineSeriesKeys
133
97
  : config.runtime.seriesKeys.map((seriesKey, index) => (
134
98
  <>
@@ -141,7 +105,7 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
141
105
  opacity={config.legend.behavior === 'highlight' && seriesHighlight.length > 0 && seriesHighlight.indexOf(seriesKey) === -1 ? 0.5 : 1}
142
106
  display={config.legend.behavior === 'highlight' || seriesHighlight.length === 0 || seriesHighlight.indexOf(seriesKey) !== -1 ? 'block' : 'none'}
143
107
  >
144
- {cleanedData.map((d, dataIndex) => {
108
+ {data.map((d, dataIndex) => {
145
109
  let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${formatNumber(getYAxisData(d, seriesKey))}` : formatNumber(getYAxisData(d, seriesKey))
146
110
  let xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${d[config.runtime.xAxis.dataKey]}` : d[config.runtime.xAxis.dataKey]
147
111
 
@@ -175,7 +139,7 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
175
139
  })}
176
140
  <LinePath
177
141
  curve={allCurves.curveLinear}
178
- data={cleanedData}
142
+ data={data}
179
143
  x={d => xScale(getXAxisData(d))}
180
144
  y={d => yScale(getYAxisData(d, seriesKey))}
181
145
  stroke={colorScale ? colorScale(config.runtime.seriesLabels ? config.runtime.seriesLabels[seriesKey] : seriesKey) : '#000'}
@@ -201,7 +165,7 @@ export default function SparkLine({ width: parentWidth, height: parentHeight })
201
165
  hideTicks
202
166
  scale={xScale}
203
167
  tickValues={handleSparkLineTicks}
204
- tickFormat={formatDate}
168
+ tickFormat={tick => (config.xAxis.type === 'date' ? formatDate(tick) : null)}
205
169
  stroke={'black'}
206
170
  tickStroke={'black'}
207
171
  tickLabelProps={() => ({
@@ -2,6 +2,7 @@ export default {
2
2
  type: 'chart',
3
3
  title: '',
4
4
  showTitle: true,
5
+ showDownloadMediaButton: false,
5
6
  theme: 'theme-blue',
6
7
  animate: false,
7
8
  fontSize: 'medium',
@@ -14,6 +15,9 @@ export default {
14
15
  barStyle: '',
15
16
  roundingStyle: 'standard',
16
17
  tipRounding: 'top',
18
+ general: {
19
+ showDownloadButton: false
20
+ },
17
21
  padding: {
18
22
  left: 5,
19
23
  right: 5
@@ -40,7 +44,8 @@ export default {
40
44
  rightAxisTickColor: '#333',
41
45
  numTicks: '',
42
46
  axisPadding: 0,
43
- tickRotation: 0
47
+ tickRotation: 0,
48
+ anchors: []
44
49
  },
45
50
  boxplot: {
46
51
  plots: [],
@@ -67,7 +72,9 @@ export default {
67
72
  iqr: 'Interquartile Range',
68
73
  total: 'Total',
69
74
  outliers: 'Outliers',
70
- values: 'Values'
75
+ values: 'Values',
76
+ lowerBounds: 'Lower Bounds',
77
+ upperBounds: 'Upper Bounds'
71
78
  }
72
79
  },
73
80
  topAxis: {
@@ -82,6 +89,7 @@ export default {
82
89
  horizontal: 750
83
90
  },
84
91
  xAxis: {
92
+ anchors: [],
85
93
  type: 'categorical',
86
94
  showTargetLabel: true,
87
95
  targetLabel: 'Target',
@@ -106,9 +114,16 @@ export default {
106
114
  limitHeight: false,
107
115
  height: '',
108
116
  caption: '',
109
- showDownloadUrl: false
117
+ showDownloadUrl: false,
118
+ showDataTableLink: true,
119
+ indexLabel: '',
120
+ download: false,
121
+ showVertical: true
110
122
  },
111
123
  orientation: 'vertical',
124
+ color: 'pinkpurple',
125
+ columns: { // start with a blank list
126
+ },
112
127
  legend: {
113
128
  behavior: 'isolate',
114
129
  singleRow: false,
@@ -146,5 +161,9 @@ export default {
146
161
  border: true,
147
162
  accent: true,
148
163
  background: true
149
- }
164
+ },
165
+ useLogScale: false,
166
+ filterBehavior: 'Filter Change',
167
+ highlightedBarValues: [],
168
+ series: []
150
169
  }
@@ -0,0 +1,154 @@
1
+ import React, { useContext } from 'react'
2
+ import ConfigContext from '../ConfigContext'
3
+
4
+ export const useHighlightedBars = (config, updateConfig) => {
5
+ const { formatDate, parseDate } = useContext(ConfigContext)
6
+
7
+ let highlightedSeries = [] // only allow single series for highlights
8
+ let highlightedSeriesKey = ''
9
+ let highlightedBarValues = []
10
+ let highlightedSeriesValues = []
11
+
12
+ if (config.series?.length > 0 && config.data) {
13
+ highlightedSeries = config.series[0] // only allow single series for highlights
14
+ highlightedSeriesKey = config.series[0].dataKey
15
+ highlightedBarValues = config.highlightedBarValues
16
+ highlightedSeriesValues = config.data.map(item => item[config.xAxis.dataKey])
17
+ } else {
18
+ highlightedSeries = [] // only allow single series for highlights
19
+ highlightedSeriesKey = ''
20
+ highlightedBarValues = []
21
+ highlightedSeriesValues = []
22
+ }
23
+
24
+ const handleUpdateHighlightedBorderWidth = (e, index) => {
25
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
26
+ copyOfHighlightedBarValues[index].borderWidth = e.target.value
27
+
28
+ updateConfig({
29
+ ...config,
30
+ highlightedBarValues: copyOfHighlightedBarValues
31
+ })
32
+ }
33
+
34
+ const handleUpdateHighlightedBar = (e, index) => {
35
+ e.preventDefault()
36
+
37
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
38
+
39
+ copyOfHighlightedBarValues[index].value = e.target.value
40
+ copyOfHighlightedBarValues[index].dataKey = highlightedSeriesKey
41
+
42
+ updateConfig({
43
+ ...config,
44
+ highlightedBarValues: copyOfHighlightedBarValues
45
+ })
46
+ }
47
+
48
+ const handleAddNewHighlightedBar = (e, index) => {
49
+ e.preventDefault()
50
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
51
+ copyOfHighlightedBarValues.push({ dataKey: highlightedSeriesKey })
52
+
53
+ updateConfig({
54
+ ...config,
55
+ highlightedBarValues: copyOfHighlightedBarValues
56
+ })
57
+ }
58
+
59
+ const handleRemoveHighlightedBar = (e, index) => {
60
+ e.preventDefault()
61
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
62
+ copyOfHighlightedBarValues.splice(index, 1)
63
+ updateConfig({
64
+ ...config,
65
+ highlightedBarValues: copyOfHighlightedBarValues
66
+ })
67
+ }
68
+
69
+ const handleUpdateHighlightedBarColor = (e, index) => {
70
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
71
+ copyOfHighlightedBarValues[index].color = e.target.value
72
+
73
+ updateConfig({
74
+ ...config
75
+ })
76
+ }
77
+
78
+ const handleHighlightedBarLegendLabel = (e, index) => {
79
+ const copyOfHighlightedBarValues = [...config.highlightedBarValues]
80
+ copyOfHighlightedBarValues[index].legendLabel = e.target.value
81
+
82
+ updateConfig({
83
+ ...config,
84
+ copyOfHighlightedBarValues
85
+ })
86
+ }
87
+
88
+ const HighLightedBarUtils = () => {}
89
+
90
+ /**
91
+ * @param {string} formattedValue - The value to check for.
92
+ * @param {Array<string>} highlightedBarValuesIn - An array of highlighted bar values.
93
+ * @param {string} labelColor - The default label color.
94
+ * @returns {string} - Returns the font color for the given value.
95
+ */
96
+ HighLightedBarUtils.checkFontColor = (formattedValue, highlightedBarValuesIn, labelColor) => {
97
+ if (config.xAxis.type === 'date') {
98
+ if (HighLightedBarUtils.formatDates(highlightedBarValuesIn).includes(formattedValue)) {
99
+ return '#000'
100
+ }
101
+ } else {
102
+ if (highlightedBarValuesIn.includes(formattedValue)) {
103
+ return '#000'
104
+ }
105
+ }
106
+ return labelColor
107
+ }
108
+
109
+ /**
110
+ * Formats an array of date values using the formatDate and parseDate functions.
111
+ *
112
+ * @param {string[]} highlightedBarValues - An array of date values to format.
113
+ * @returns {?Date[]} - An array of formatted date objects, or null if invalid input is provided.
114
+ */
115
+ HighLightedBarUtils.formatDates = highlightedBarValues => {
116
+ return highlightedBarValues.map(dateItem => {
117
+ if (!dateItem) return false
118
+ return formatDate(parseDate(dateItem))
119
+ })
120
+ }
121
+
122
+ /**
123
+ * Finds duplicate objects in an array based on the legendLabel property.
124
+ *
125
+ * @param {Array} arr - The array of objects to be checked.
126
+ * @return {Array} - An array of arrays, each containing objects that have the same legendLabel property.
127
+ */
128
+ HighLightedBarUtils.findDuplicates = arr => {
129
+ const duplicates = {}
130
+ const result = arr.filter(obj => {
131
+ const { legendLabel } = obj
132
+ if (!duplicates[legendLabel]) {
133
+ duplicates[legendLabel] = true
134
+ return true
135
+ }
136
+ return false
137
+ })
138
+ return result
139
+ }
140
+
141
+ return {
142
+ HighLightedBarUtils,
143
+ highlightedSeries,
144
+ highlightedSeriesKey,
145
+ highlightedBarValues,
146
+ highlightedSeriesValues,
147
+ handleUpdateHighlightedBar,
148
+ handleAddNewHighlightedBar,
149
+ handleRemoveHighlightedBar,
150
+ handleUpdateHighlightedBarColor,
151
+ handleHighlightedBarLegendLabel,
152
+ handleUpdateHighlightedBorderWidth
153
+ }
154
+ }
@@ -0,0 +1,92 @@
1
+ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAllLine }) => {
2
+ let min = 0
3
+ let max = 0
4
+
5
+ if (!data) {
6
+ return { min, max }
7
+ }
8
+
9
+ const { max: enteredMaxValue, min: enteredMinValue } = config.runtime.yAxis
10
+
11
+ // do validation bafore applying t0 charts
12
+ const isMaxValid = existPositiveValue ? enteredMaxValue >= maxValue : enteredMaxValue >= 0
13
+ const isMinValid = config.useLogScale ? enteredMinValue >= 0 : (enteredMinValue <= 0 && minValue >= 0) || (enteredMinValue <= minValue && minValue < 0)
14
+
15
+ min = enteredMinValue && isMinValid ? enteredMinValue : minValue
16
+ max = enteredMaxValue && isMaxValid ? enteredMaxValue : Number.MIN_VALUE
17
+
18
+ if (config.visualizationType === 'Bar' || config.visualizationType === 'Combo' || config.visualizationType === 'Deviation Bar') {
19
+ let ciYMax = 0
20
+ if (config.hasOwnProperty('confidenceKeys')) {
21
+ let upperCIValues = data.map(function (d) {
22
+ return d[config.confidenceKeys.upper]
23
+ })
24
+ ciYMax = Math.max.apply(Math, upperCIValues)
25
+ if (ciYMax > max) max = ciYMax // bump up the max
26
+ }
27
+ }
28
+
29
+ if ((config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && !isAllLine)) && min > 0) {
30
+ min = 0
31
+ }
32
+ if (config.visualizationType === 'Combo' && isAllLine) {
33
+ if ((enteredMinValue === undefined || enteredMinValue === null || enteredMinValue === '') && min > 0) {
34
+ min = 0
35
+ }
36
+ if (enteredMinValue) {
37
+ const isMinValid = config.useLogScale ? enteredMinValue >= 0 && enteredMinValue < minValue : enteredMinValue < minValue
38
+ min = enteredMinValue && isMinValid ? enteredMinValue : minValue
39
+ }
40
+ }
41
+
42
+ if (config.visualizationType === 'Deviation Bar' && min > 0) {
43
+ const isMinValid = Number(enteredMinValue) < Math.min(minValue, Number(config.xAxis.target))
44
+ min = enteredMinValue && isMinValid ? enteredMinValue : 0
45
+ }
46
+
47
+ if (config.visualizationType === 'Line') {
48
+ const isMinValid = config.useLogScale ? enteredMinValue >= 0 && enteredMinValue < minValue : enteredMinValue < minValue
49
+ min = enteredMinValue && isMinValid ? enteredMinValue : minValue
50
+ }
51
+ //If data value max wasn't provided, calculate it
52
+ if (max === Number.MIN_VALUE) {
53
+ // if all values in data are negative set max = 0
54
+ max = existPositiveValue ? maxValue : 0
55
+ }
56
+
57
+ //Adds Y Axis data padding if applicable
58
+ if (config.runtime.yAxis.paddingPercent) {
59
+ let paddingValue = (max - min) * config.runtime.yAxis.paddingPercent
60
+ min -= paddingValue
61
+ max += paddingValue
62
+ }
63
+
64
+ if (config.isLollipopChart && config.yAxis.displayNumbersOnBar) {
65
+ const dataKey = data.map(item => item[config.series[0].dataKey])
66
+ const maxDataVal = Math.max(...dataKey).toString().length
67
+
68
+ switch (true) {
69
+ case maxDataVal > 8 && maxDataVal <= 12:
70
+ max = max * 1.3
71
+ break
72
+ case maxDataVal > 4 && maxDataVal <= 7:
73
+ max = max * 1.1
74
+ break
75
+ default:
76
+ break
77
+ }
78
+ }
79
+
80
+ if (config.yAxis.enablePadding) {
81
+ if (min < 0) {
82
+ // sets with negative data need more padding on the max
83
+ max *= 1.2
84
+ min *= 1.2
85
+ } else {
86
+ max *= 1.1
87
+ }
88
+ }
89
+
90
+ return { min, max }
91
+ }
92
+ export default useMinMax
@@ -1,81 +1,55 @@
1
1
  import isNumber from '@cdc/core/helpers/isNumber'
2
2
 
3
3
  function useReduceData(config, data) {
4
- // for combo charts check if all Data Series selected to Bar;
5
- const isBar = config?.series?.every(element => element?.type === 'Bar')
6
- // for combo charts check if all Data series selected Line or dashed-md/sm/lg.
7
- const isAllLine = config?.series?.every(el => el.type === 'Line' || el.type === 'dashed-sm' || el.type === 'dashed-md' || el.type === 'dashed-lg')
8
- const cleanChars = value => {
9
- // remove comma and $ signs
10
- let tmp
11
- if (typeof value === 'string') {
12
- tmp = value !== null && value !== '' ? value.replace(/[,$]/g, '') : ''
13
- } else {
14
- tmp = value !== null && value !== '' ? value : ''
15
- }
16
- return tmp
17
- }
4
+ const isBar = config.series.every(({ type }) => type === 'Bar')
5
+ const isAllLine = config.series.every(({ type }) => ['Line', 'dashed-sm', 'dashed-md', 'dashed-lg'].includes(type))
6
+ const sumYValues = seriesKeys => xValue => seriesKeys.reduce((yTotal, k) => yTotal + Number(xValue[k]), 0)
7
+
18
8
  const getMaxValueFromData = () => {
19
- let max // will hold max number from data.
20
- if ((config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && isBar)) && config.visualizationSubType === 'stacked') {
21
- const yTotals = data.reduce((allTotals, xValue) => {
22
- const totalYValues = config.runtime.seriesKeys.reduce((yTotal, k) => {
23
- yTotal += Number(xValue[k])
24
- return yTotal
25
- }, 0)
26
-
27
- allTotals.push(totalYValues)
28
- if (totalYValues > max) {
29
- max = totalYValues
30
- }
31
- return allTotals
32
- }, [])
9
+ let max = Math.max(...data.map(d => Math.max(...config.runtime.seriesKeys.map(key => (isNumber(d[key]) ? Number(cleanChars(d[key])) : 0)))))
33
10
 
11
+ if ((config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && isBar)) && config.visualizationSubType === 'stacked') {
12
+ const yTotals = data.map(sumYValues(config.runtime.seriesKeys))
34
13
  max = Math.max(...yTotals)
35
- } else if ((config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.series && config.series.dataKey) {
14
+ }
15
+
16
+ if ((config.visualizationType === 'Bar' || config.visualizationType === 'Deviation Bar') && config.series && config.series.dataKey) {
36
17
  max = Math.max(...data.map(d => (isNumber(d[config.series.dataKey]) ? Number(cleanChars(d[config.series.dataKey])) : 0)))
37
- //max = Math.max(...data.map(d => Number(d[config.series.dataKey])))
38
- } else if (config.visualizationType === 'Combo' && config.visualizationSubType === 'stacked' && !isBar) {
39
- let total = []
18
+ }
40
19
 
20
+ if (config.visualizationType === 'Combo' && config.visualizationSubType === 'stacked' && !isBar) {
41
21
  if (config.runtime.barSeriesKeys && config.runtime.lineSeriesKeys) {
42
- // get barSeries max Values added to each other
43
- data.map(function (d, index) {
44
- const totalYValues = config.runtime.barSeriesKeys.reduce((yTotal, k) => {
45
- yTotal += Number(d[k])
46
- return yTotal
47
- }, 0)
48
- return total.push(totalYValues)
49
- })
50
- // get lineSeries largest values
51
- const lineMax = Math.max(...data.map(d => Math.max(...config.runtime.lineSeriesKeys.map(key => Number(cleanChars(d[key]))))))
22
+ const yTotals = data.map(sumYValues(config.runtime.barSeriesKeys))
52
23
 
53
- const barMax = Math.max(...total)
24
+ const lineMax = Math.max(...data.map(d => Math.max(...config.runtime.lineSeriesKeys.map(key => Number(cleanChars(d[key]))))))
25
+ const barMax = Math.max(...yTotals)
54
26
 
55
- max = Number(barMax) > Number(lineMax) ? barMax : lineMax
27
+ max = Math.max(barMax, lineMax)
56
28
  }
57
- } else {
58
- max = Math.max(...data.map(d => Math.max(...config.runtime.seriesKeys.map(key => (isNumber(d[key]) ? Number(cleanChars(d[key])) : 0)))))
59
29
  }
30
+
60
31
  return max
61
32
  }
62
33
 
63
34
  const getMinValueFromData = () => {
64
- let min
65
- const minNumberFromData = Math.min(...data.map(d => Math.min(...config.runtime.seriesKeys.map(key => (isNumber(d[key]) ? Number(cleanChars(d[key])) : 1000000000)))))
66
- min = String(minNumberFromData)
67
- return min
35
+ const minNumberFromData = Math.min(...data.map(d => Math.min(...config.runtime.seriesKeys.map(key => (isNumber(d[key]) ? Number(cleanChars(d[key])) : Infinity)))))
36
+
37
+ return String(minNumberFromData)
68
38
  }
69
39
 
70
40
  const findPositiveNum = () => {
71
- // loop throught provided data to find positve number in arr based on series keys.
72
- let existPositiveValue = false
73
- if (config.runtime.seriesKeys) {
74
- for (let i = 0; i < config.runtime.seriesKeys.length; i++) {
75
- existPositiveValue = data.some(d => d[config.runtime.seriesKeys[i]] >= 0)
76
- }
41
+ if (!config.runtime.seriesKeys) {
42
+ return false
77
43
  }
78
- return existPositiveValue
44
+ return config.runtime.seriesKeys.some(key => data.some(d => d[key] >= 0))
45
+ }
46
+
47
+ const cleanChars = value => {
48
+ if (value === null || value === '') {
49
+ return ''
50
+ }
51
+
52
+ return typeof value === 'string' ? value.replace(/[,$]/g, '') : value
79
53
  }
80
54
 
81
55
  const maxValue = Number(getMaxValueFromData())