@cdc/chart 4.23.8 → 4.23.9

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.
package/index.html CHANGED
@@ -34,10 +34,10 @@
34
34
  -->
35
35
 
36
36
  <!-- GENERIC CHART TYPES -->
37
- <div class="react-container" data-config="/examples/private/tooltip-issue.json"></div>
37
+ <!-- <div class="react-container" data-config="/examples/private/double.json"></div> -->
38
38
  <!-- <div class="react-container" data-config="https://cdc.gov/poxvirus/mpox/modules/data-viz/mpx-trends_1.json"></div> -->
39
39
  <!-- <div class="react-container" data-config="/examples/private/mpox-bar-test-aug-31.json"></div> -->
40
- <!-- <div class="react-container" data-config="/examples/feature/area/area-chart-date-city-temperature.json"></div> -->
40
+ <div class="react-container" data-config="/examples/feature/area/area-chart-date-city-temperature.json"></div>
41
41
  <!-- <div class="react-container" data-config="/examples/feature/area/area-chart-date-apple.json"></div> -->
42
42
  <!-- <div class="react-container" data-config="/examples/feature/forest-plot/broken.json"></div> -->
43
43
  <!-- <div class="react-container" data-config="/examples/feature/forest-plot/forest-plot.json"></div> -->
@@ -46,7 +46,7 @@
46
46
  <!-- <div class="react-container" data-config="/examples/feature/forecasting/forecasting.json"></div> -->
47
47
  <!-- <div class="react-container" data-config="/examples/feature/forecasting/combo-forecasting.json"></div> -->
48
48
  <!-- <div class="react-container" data-config="/examples/feature/forecasting/effective_reproduction.json"></div> -->
49
- <div class="react-container" data-config="/examples/feature/area/area-chart-date.json"></div>
49
+ <!-- <div class="react-container" data-config="/examples/feature/area/area-chart-date.json"></div> -->
50
50
  <!-- <div class="react-container" data-config="/examples/feature/area/area-chart-category.json"></div> -->
51
51
  <!-- <div class="react-container" data-config="/examples/feature/scatterplot/scatterplot.json"></div> -->
52
52
  <!-- <div class="react-container" data-config="/examples/feature/deviation/planet-deviation-config.json"></div> -->
@@ -60,13 +60,31 @@
60
60
  <!-- <div class="react-container" data-config="/examples/feature/bar/planet-chart-horizontal-example-config.json"></div> -->
61
61
  <!-- <div class="react-container" data-config="/examples/feature/bar/example-bar-chart.json"></div> -->
62
62
  <!-- <div class="react-container" data-config="/examples/feature/bar/horizontal-chart-max-increase.json"></div> -->
63
- <div class="react-container" data-config="/examples/feature/bar/horizontal-chart.json"></div>
63
+ <!-- <div class="react-container" data-config="/examples/feature/bar/horizontal-chart.json"></div> -->
64
64
  <!-- <div class="react-container" data-config="/examples/feature/bar/horizontal-stacked-bar-chart.json"></div> -->
65
65
  <!-- <div class="react-container" data-config="/examples/feature/bar/planet-chart-horizontal-example-config.json"></div> -->
66
66
 
67
67
  <!-- SPARKLINE -->
68
68
  <!-- <div class="react-container" data-config="/examples/feature/sparkline/example-sparkline.json"></div> -->
69
69
 
70
+ <!-- TESTS DATA TABLE SORTING -->
71
+ <!-- Bar Chart with Confidence Intervals (bottom of page) -->
72
+ <!-- <div class="react-container" data-config="https://www.cdc.gov/wcms/4.0/cdc-wp/data-presentation/examples/Example_Bar_CI.json"></div> -->
73
+ <!-- TPOXX Patient Data -->
74
+ <!-- <div class="react-container" data-config="https://www.cdc.gov/poxvirus/mpox/modules/data-viz/tpoxx_weekly_race_eth.json"></div> -->
75
+ <!-- <div class="react-container" data-config="https://www.cdc.gov/poxvirus/mpox/modules/data-viz/mpx-tpoxx-age-gender.json"></div> -->
76
+ <!-- Non-Variola Orthopoxvirus (NVO) Laboratory Testing by Demographics -->
77
+ <!-- <div class="react-container" data-config="https://wwwdev-cdc.msappproxy.net/poxvirus/mpox/modules/data-viz/lab-data.json"></div> -->
78
+ <!-- <div class="react-container" data-config="https://wwwdev-cdc.msappproxy.net/poxvirus/mpox/modules/data-viz/lab-data-age.json"></div> -->
79
+ <!-- PROBLEM WITH THEIR PAGE CONFIG or CONFLICT with -->
80
+ <!-- <div class="react-container" data-config="/examples/private/outbreak-repro-bug.json"></div> -->
81
+ <!-- CORS ERROR pulling data on Covid Flu RSV page at https://wwwdev-cdc.msappproxy.net/respiratory-viruses/index.html-->
82
+ <!-- <div class="react-container" data-config="https://wwwdev-cdc.msappproxy.net/respiratory-viruses/modules/emergency-dept-visits_live.json"></div> -->
83
+ <!-- MPOX -->
84
+ <!-- <div class="react-container" data-config="https://www.cdc.gov/poxvirus/mpox/modules/data-viz/mpox-demographics-monthly.json"></div> -->
85
+ <!-- <div class="react-container" data-config="/https://www.cdc.gov/poxvirus/mpox/modules/data-viz/mpx-age-sex1.json"></div> -->
86
+
87
+
70
88
  <!-- TESTS DATE EXCLUSIONS -->
71
89
  <!-- <div class="react-container" data-config="/examples/feature/tests-date-exclusions/date-exclusions-config.json"></div> -->
72
90
  <!-- <div class="react-container" data-config="/examples/feature/tests-case-rate/case-rate-example-config.json"></div> -->
@@ -112,7 +130,7 @@
112
130
  <!-- <div class="react-container" data-config="/examples/gallery/bar-chart-vertical/vertical-bar-chart-stacked.json"></div> -->
113
131
  <!-- <div class="react-container" data-config="/examples/gallery/bar-chart-vertical/vertical-bar-chart-confidence.json"></div> -->
114
132
  <!-- <div class="react-container" data-config="/examples/gallery/bar-chart-vertical/vertical-bar-chart-confidence.json"></div> -->
115
- <div class="react-container" data-config="/examples/gallery/bar-chart-vertical/vertical-bar-chart.json"></div>
133
+ <!-- <div class="react-container" data-config="/examples/gallery/bar-chart-vertical/vertical-bar-chart.json"></div> -->
116
134
 
117
135
  <noscript>You need to enable JavaScript to run this app.</noscript>
118
136
  </body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cdc/chart",
3
- "version": "4.23.8",
3
+ "version": "4.23.9",
4
4
  "description": "React component for visualizing tabular data in various types of charts",
5
5
  "moduleName": "CdcChart",
6
6
  "main": "dist/cdcchart",
@@ -58,7 +58,7 @@
58
58
  "react": "^18.2.0",
59
59
  "react-dom": "^18.2.0"
60
60
  },
61
- "gitHead": "ba0a072a40c430baf121ad5ece0165f52a414b86",
61
+ "gitHead": "1a737cd5d226963d5ad9c6efb8d59e4a1311141c",
62
62
  "devDependencies": {
63
63
  "resize-observer-polyfill": "^1.5.1"
64
64
  }
@@ -27,6 +27,8 @@ const BarChartStackedVertical = props => {
27
27
  const xAxisValue = config.runtime.xAxis.type === 'date' ? formatDate(parseDate(data[bar.index][config.runtime.xAxis.dataKey])) : data[bar.index][config.runtime.xAxis.dataKey]
28
28
  const yAxisValue = formatNumber(bar.bar ? bar.bar.data[bar.key] : 0, 'left')
29
29
 
30
+ if(!yAxisValue) return <></>
31
+
30
32
  const style = applyRadius(barStack.index)
31
33
  let yAxisTooltip = config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ${yAxisValue}` : yAxisValue
32
34
  const xAxisTooltip = config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ${xAxisValue}` : xAxisValue
@@ -13,7 +13,10 @@ import ConfigContext from '../ConfigContext'
13
13
 
14
14
  import MediaControls from '@cdc/core/components/MediaControls'
15
15
 
16
- export default function DataTable() {
16
+ const DataTable = props => {
17
+ // had to pass in runtimeData as prop to get the raw prop names in the inbound data (TT)
18
+ const { runtimeData, isDebug } = props
19
+
17
20
  const { rawData, tableData: data, config, colorScale, parseDate, formatDate, formatNumber: numberFormatter, colorPalettes, currentViewport } = useContext(ConfigContext)
18
21
 
19
22
  const section = config.orientation === 'horizontal' ? 'yAxis' : 'xAxis'
@@ -150,7 +153,8 @@ export default function DataTable() {
150
153
  },
151
154
  id: `${d[config.runtime.originalXAxis.dataKey]}--${index}`,
152
155
  sortType: 'custom',
153
- canSort: true
156
+ canSort: true,
157
+ defaultCanSort: true
154
158
  }
155
159
 
156
160
  newTableColumns.push(newCol)
@@ -231,7 +235,9 @@ export default function DataTable() {
231
235
  <path d='M0 0l5 5 5-5z' />
232
236
  </svg>
233
237
  )
234
-
238
+ const getSpecificCellData = (array, value) => {
239
+ return array.filter(data => JSON.stringify(data).toLowerCase().indexOf(value.toLowerCase()) !== -1)
240
+ }
235
241
  const { getTableProps, getTableBodyProps, headerGroups, rows, prepareRow } = useTable(
236
242
  {
237
243
  columns: tableColumns,
@@ -240,27 +246,139 @@ export default function DataTable() {
240
246
  disableSortRemove: true, // otherwise 3rd click on header removes sorting entirely
241
247
  sortTypes: {
242
248
  custom: (rowA, rowB, columnId) => {
249
+ // NOTE:
250
+ // 1) Main issue causing all this code:
251
+ // rowA and rowB are coming in with all values undefined
252
+ // - if it passed the values we could just use the columnId to get the correct sort value
253
+ // but since it's not there we have to go through a bunch of code to get it because
254
+ // we also do not know the Y axis data key (TT)
255
+ // 2). if formattedData did not truncate the strings we could get it from there
256
+ // but Hispanic or Latino is truncated to just Hispanic as the key
257
+ // and 'White, Non-Hispanic/Latino' gets truncated to remove the /Latino
258
+
243
259
  // rowA.original - is the row data field name to access the value
244
- // columnId = the column indicator
260
+ // columnId = the column indicator typically date or date--index
261
+ let a, b
262
+ if (columnId === 'series-label') {
263
+ // comparing strings
264
+ a = rowA.original
265
+ b = rowB.original
266
+ return a.localeCompare(b)
267
+ }
268
+
245
269
  let dataKey = config.xAxis.dataKey
246
- let colObj = config.data.filter(obj => {
247
- return obj[dataKey] === columnId.split('--')[0] // have to remove index
270
+ let columnIdIndexRemoved = columnId.split('--')[0] // have to remove index for compare
271
+ //get all the data from that column
272
+ let colData = runtimeData.filter(obj => {
273
+ // problem is dates can be in different formats
274
+ if (config.xAxis.type === 'date' && !isNaN(Date.parse(obj[dataKey])) && !isNaN(Date.parse(columnIdIndexRemoved))) {
275
+ // must convert to datetime number to compare
276
+ return parseDate(obj[dataKey]).getTime() === parseDate(columnIdIndexRemoved).getTime()
277
+ } else {
278
+ return obj[dataKey] === columnIdIndexRemoved // have to remove index
279
+ }
248
280
  })
249
- if (colObj === undefined || colObj[0] === undefined) {
281
+
282
+ if (colData === undefined || colData[0] === undefined) {
250
283
  return -1
251
284
  }
252
- // NOW we can get the sort values
253
- const a = transform.cleanDataPoint(colObj[0][rowA.original]) // issue was that a was UNDEFINED therefore it CANT SORT
254
- const b = transform.cleanDataPoint(colObj[0][rowB.original])
255
285
 
256
- if (a === undefined) {
286
+ let rowA_cellObj = getSpecificCellData(colData, rowA.original)
287
+ let rowB_cellObj = getSpecificCellData(colData, rowB.original)
288
+
289
+ // - ** REMOVE any data points NOT selected in the data series ***
290
+ // I dont understand why not selected data series are still sent down in the data
291
+ // - would be better to scrub outside of here (TT)
292
+ let newRowA_cellObj = []
293
+ let newRowB_cellObj = []
294
+ if (config.runtime.seriesKeys) {
295
+ config.runtime.seriesKeys.forEach(seriesKey => {
296
+ if (seriesKey in rowA_cellObj[0]) newRowA_cellObj.push(rowA_cellObj[0][seriesKey])
297
+ if (seriesKey in rowB_cellObj[0]) newRowB_cellObj.push(rowB_cellObj[0][seriesKey])
298
+ })
299
+ // copy back over
300
+ rowA_cellObj[0] = newRowA_cellObj
301
+ rowB_cellObj[0] = newRowB_cellObj
302
+ }
303
+
304
+ // REMOVE the following:
305
+ // - value equal to column date
306
+ // - value that is the .original
307
+ // - any data still in that's not really a number
308
+ let rowA_valueObj = Object.values(rowA_cellObj[0]).filter(value => value !== columnIdIndexRemoved && value !== rowA.original && !isNaN(value))
309
+ let rowB_valueObj = Object.values(rowB_cellObj[0]).filter(value => value !== columnIdIndexRemoved && value !== rowB.original && !isNaN(value))
310
+
311
+ // NOW we can get the sort values from the cell object
312
+ a = rowA_valueObj.length > 1 ? rowA_valueObj[rowA.id] : rowA_valueObj[0]
313
+ b = rowB_valueObj.length > 1 ? rowB_valueObj[rowB.id] : rowB_valueObj[0]
314
+
315
+ // force null and undefined to the bottom
316
+ a = a === null || a === undefined ? '' : transform.cleanDataPoint(a)
317
+ b = b === null || b === undefined ? '' : transform.cleanDataPoint(b)
318
+ if (a === '' || a === null) {
319
+ if (b === '' || b === null) {
320
+ return 0 // Both empty/null
321
+ }
322
+ return -1 // Sort a to an index lower than b
323
+ }
324
+ if (b === '' || b === null) {
325
+ if (a === '' || a === null) {
326
+ return 0 // Both empty/null
327
+ }
328
+ return 1 // Sort b to an index lower than a
329
+ }
330
+ // End code for forcing NULLS to bottom
331
+
332
+ // convert any strings that are actually numbers to proper data type
333
+ const aNum = Number(a)
334
+
335
+ if (!Number.isNaN(aNum)) {
336
+ a = aNum
337
+ }
338
+
339
+ const bNum = Number(b)
340
+
341
+ if (!Number.isNaN(bNum)) {
342
+ b = bNum
343
+ }
344
+ // remove iso code prefixes
345
+ if (typeof a === 'string') {
346
+ a = a.replace('us-', '')
347
+ a = displayGeoName(a)
348
+ }
349
+
350
+ if (typeof b === 'string') {
351
+ b = b.replace('us-', '')
352
+ b = displayGeoName(b)
353
+ }
354
+
355
+ // force any string values to lowercase
356
+ a = typeof a === 'string' ? a.toLowerCase() : a
357
+ b = typeof b === 'string' ? b.toLowerCase() : b
358
+
359
+ // When comparing a number to a string, always send string to bottom
360
+ if (typeof a === 'number' && typeof b === 'string') {
361
+ return 1
362
+ }
363
+
364
+ if (typeof b === 'number' && typeof a === 'string') {
257
365
  return -1
258
366
  }
259
- if (!isNaN(Number(a)) && !isNaN(Number(b))) {
260
- return Number(a) - Number(b)
367
+
368
+ // Return either 1 or -1 to indicate a sort priority
369
+ if (a > b) {
370
+ return 1
371
+ }
372
+ if (a < b) {
373
+ return -1
261
374
  }
262
- return a.localeCompare(b)
375
+ // returning 0, undefined or any falsey value will use subsequent sorts or
376
+ // the index as a tiebreaker
377
+ return 0
263
378
  }
379
+ },
380
+ initialState: {
381
+ sortBy: [{ id: 'series-label', desc: false }] // default sort on 1st column -
264
382
  }
265
383
  },
266
384
  useSortBy,
@@ -372,3 +490,5 @@ export default function DataTable() {
372
490
  </ErrorBoundary>
373
491
  )
374
492
  }
493
+
494
+ export default DataTable
@@ -1826,6 +1826,7 @@ const EditorPanel = () => {
1826
1826
  {config.visualizationType !== 'Forest Plot' && (
1827
1827
  <Select value={config.xAxis.type} section='xAxis' fieldName='type' label='Data Type' updateField={updateField} options={config.visualizationType !== 'Scatter Plot' ? ['categorical', 'date'] : ['categorical', 'continuous', 'date']} />
1828
1828
  )}
1829
+ <CheckBox value={config.xAxis.sortDates} section='xAxis' fieldName='sortDates' label='Force Date Scale (Sort Dates)' updateField={updateField} />{' '}
1829
1830
  <Select
1830
1831
  value={config.xAxis.dataKey || setCategoryAxis() || ''}
1831
1832
  section='xAxis'
@@ -2678,13 +2679,20 @@ const EditorPanel = () => {
2678
2679
 
2679
2680
  {config.visualizationType !== 'Box Plot' && <CheckBox value={config.legend.showLegendValuesTooltip ? true : false} section='legend' fieldName='showLegendValuesTooltip' label='Show Legend Values in Tooltip' updateField={updateField} />}
2680
2681
 
2682
+ {config.visualizationType === 'Line' && <CheckBox value={config.legend.lineMode} section='legend' fieldName='lineMode' label='Show Lined Style Legend' updateField={updateField} />}
2683
+
2681
2684
  {config.visualizationType === 'Bar' && config.visualizationSubType === 'regular' && config.runtime.seriesKeys.length === 1 && (
2682
2685
  <Select value={config.legend.colorCode} section='legend' fieldName='colorCode' label='Color code by category' initial='Select' updateField={updateField} options={getDataValueOptions(data)} />
2683
2686
  )}
2684
2687
  <Select value={config.legend.behavior} section='legend' fieldName='behavior' label='Legend Behavior (When clicked)' updateField={updateField} options={['highlight', 'isolate']} />
2685
2688
  <TextField value={config.legend.label} section='legend' fieldName='label' label='Title' updateField={updateField} />
2686
2689
  <Select value={config.legend.position} section='legend' fieldName='position' label='Position' updateField={updateField} options={['right', 'left', 'bottom']} />
2687
- {config.legend.position === 'bottom' && <CheckBox value={config.legend.singleRow} section='legend' fieldName='singleRow' label='Single Row Legend' updateField={updateField} />}
2690
+ {config.legend.position === 'bottom' && (
2691
+ <>
2692
+ <CheckBox value={config.legend.singleRow} section='legend' fieldName='singleRow' label='Single Row Legend' updateField={updateField} />
2693
+ <CheckBox value={config.legend.verticalSorted} section='legend' fieldName='verticalSorted' label='Vertical sorted Legend' updateField={updateField} />
2694
+ </>
2695
+ )}
2688
2696
  <TextField type='textarea' value={config.legend.description} updateField={updateField} section='legend' fieldName='description' label='Legend Description' />
2689
2697
  </AccordionItemPanel>
2690
2698
  </AccordionItem>
@@ -3175,7 +3183,7 @@ const EditorPanel = () => {
3175
3183
  {isDashboard && <CheckBox value={config.table.showDataTableLink} section='table' fieldName='showDataTableLink' label='Show Data Table Name & Link' updateField={updateField} />}
3176
3184
  {isLoadedFromUrl && <CheckBox value={config.table.showDownloadUrl} section='table' fieldName='showDownloadUrl' label='Show URL to Automatically Updated Data' updateField={updateField} />}
3177
3185
  <CheckBox value={config.table.download} section='table' fieldName='download' label='Show Download CSV Link' updateField={updateField} />
3178
- {/* <CheckBox value={config.table.showDownloadImgButton} section='table' fieldName='showDownloadImgButton' label='Display Image Button' updateField={updateField} /> */}
3186
+ <CheckBox value={config.table.showDownloadImgButton} section='table' fieldName='showDownloadImgButton' label='Display Image Button' updateField={updateField} />
3179
3187
  {/* <CheckBox value={config.table.showDownloadPdfButton} section='table' fieldName='showDownloadPdfButton' label='Display PDF Button' updateField={updateField} /> */}
3180
3188
  </AccordionItemPanel>
3181
3189
  </AccordionItem>
@@ -6,6 +6,7 @@ import LegendCircle from '@cdc/core/components/LegendCircle'
6
6
 
7
7
  import useLegendClasses from './../hooks/useLegendClasses'
8
8
  import { useHighlightedBars } from '../hooks/useHighlightedBars'
9
+ import { Line } from '@visx/shape'
9
10
 
10
11
  // * FILE REVIEW *
11
12
  // TODO: fix eslint-disable jsxa11y issues
@@ -28,7 +29,8 @@ const Legend = () => {
28
29
  highlightReset,
29
30
  transformedData: data,
30
31
  colorPalettes,
31
- currentViewport
32
+ currentViewport,
33
+ handleLineType
32
34
  } = useContext(ConfigContext)
33
35
 
34
36
  const { innerClasses, containerClasses } = useLegendClasses(config)
@@ -165,7 +167,6 @@ const Legend = () => {
165
167
  const { HighLightedBarUtils } = useHighlightedBars(config)
166
168
 
167
169
  let highLightedLegendItems = HighLightedBarUtils.findDuplicates(config.highlightedBarValues)
168
-
169
170
  if (!legend) return null
170
171
 
171
172
  return (
@@ -213,7 +214,14 @@ const Legend = () => {
213
214
  highlight(label)
214
215
  }}
215
216
  >
216
- <LegendCircle fill={label.value} />
217
+ {config.visualizationType === 'Line' && config.legend.lineMode ? (
218
+ <svg width={40} height={20}>
219
+ <Line from={{ x: 10, y: 10 }} to={{ x: 40, y: 10 }} stroke={label.value} strokeWidth={2} strokeDasharray={handleLineType(config.series[i]?.type ? config.series[i]?.type : '')} />
220
+ </svg>
221
+ ) : (
222
+ <LegendCircle fill={label.value} />
223
+ )}
224
+
217
225
  <LegendLabel align='left' margin='0 0 0 4px'>
218
226
  {label.text}
219
227
  </LegendLabel>
@@ -92,6 +92,7 @@ export default {
92
92
  horizontal: 750
93
93
  },
94
94
  xAxis: {
95
+ sortDates: false,
95
96
  anchors: [],
96
97
  type: 'categorical',
97
98
  showTargetLabel: true,
@@ -139,7 +140,9 @@ export default {
139
140
  dynamicLegendDefaultText: 'Show All',
140
141
  dynamicLegendItemLimit: 5,
141
142
  dynamicLegendItemLimitMessage: 'Dynamic Legend Item Limit Hit.',
142
- dynamicLegendChartMessage: 'Select Options from the Legend'
143
+ dynamicLegendChartMessage: 'Select Options from the Legend',
144
+ lineMode: false,
145
+ verticalSorted: false
143
146
  },
144
147
  exclusions: {
145
148
  active: false,
@@ -2,24 +2,27 @@ export default function useLegendClasses(config) {
2
2
  let containerClasses = ['legend-container']
3
3
  let innerClasses = ['legend-container__inner']
4
4
 
5
- // Legend Positioning
6
- if (config.legend.position === "left") {
7
- containerClasses.push('left')
8
- }
9
- if (config.legend.position === "bottom") {
10
- containerClasses.push('bottom')
11
- innerClasses.push('bottom')
12
- }
5
+ // Legend Positioning
6
+ if (config.legend.position === 'left') {
7
+ containerClasses.push('left')
8
+ }
9
+ if (config.legend.position === 'bottom') {
10
+ containerClasses.push('bottom')
11
+ innerClasses.push('bottom')
12
+ }
13
13
 
14
- if(config.legend.position==='bottom' && config.legend.singleRow){
15
- innerClasses.push('single-row')
16
- }
14
+ if (config.legend.position === 'bottom' && config.legend.singleRow) {
15
+ innerClasses.push('single-row')
16
+ }
17
17
 
18
18
  // Legend > Item Ordering
19
19
  if (config.legend.reverseLabelOrder) {
20
20
  innerClasses.push('d-flex')
21
21
  innerClasses.push('flex-column-reverse')
22
22
  }
23
+ if (config.legend.position === 'bottom' && config.legend.verticalSorted) {
24
+ innerClasses.push('vertical-sorted')
25
+ }
23
26
 
24
27
  return {
25
28
  containerClasses,
@@ -3,13 +3,13 @@ import isNumber from '@cdc/core/helpers/isNumber'
3
3
  function useReduceData(config, data) {
4
4
  const isBar = config.series.every(({ type }) => type === 'Bar')
5
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)
6
+ const sumYValues = seriesKeys => xValue => seriesKeys.reduce((yTotal, k) => (isNaN(Number(xValue[k])) ? yTotal : yTotal + Number(xValue[k])), 0)
7
7
 
8
8
  const getMaxValueFromData = () => {
9
9
  let max = Math.max(...data.map(d => Math.max(...config.runtime.seriesKeys.map(key => (isNumber(d[key]) ? Number(cleanChars(d[key])) : 0)))))
10
10
 
11
11
  if ((config.visualizationType === 'Bar' || (config.visualizationType === 'Combo' && isBar)) && config.visualizationSubType === 'stacked') {
12
- const yTotals = data.map(sumYValues(config.runtime.seriesKeys))
12
+ const yTotals = data.map(sumYValues(config.runtime.seriesKeys)).filter(num => !isNaN(num))
13
13
  max = Math.max(...yTotals)
14
14
  }
15
15
 
@@ -48,7 +48,7 @@ const useScales = properties => {
48
48
  }
49
49
 
50
50
  // handle Area chart
51
- if (config.visualizationType === 'Area Chart' && config.xAxis.type === 'date') {
51
+ if (config.xAxis.type === 'date' && config.xAxis.sortDates) {
52
52
  xScale = scaleTime({
53
53
  domain: [Math.min(...xAxisDataMapped), Math.max(...xAxisDataMapped)],
54
54
  range: [0, xMax]
@@ -170,7 +170,7 @@ export const useTooltip = props => {
170
170
  const getXValueFromCoordinate = x => {
171
171
  if (visualizationType === 'Pie') return
172
172
  if (orientation === 'horizontal') return
173
- if (xScale.type === 'point' || xAxis.type === 'continuous') {
173
+ if (xScale.type === 'point' || xAxis.type === 'continuous' || xAxis.type === 'date') {
174
174
  // Find the closest x value by calculating the minimum distance
175
175
  let closestX = null
176
176
  let minDistance = Number.MAX_VALUE
@@ -315,7 +315,7 @@ export const useTooltip = props => {
315
315
  if (!config.dashboard) {
316
316
  switch (visualizationType) {
317
317
  case 'Combo':
318
- standardLoopItems = [runtime.xAxis.dataKey, ...runtime?.barSeriesKeys, ...runtime?.lineSeriesKeys, ...stageColumns, ...ciItems]
318
+ standardLoopItems = [runtime.xAxis.dataKey, ...runtime?.seriesKeys, ...stageColumns, ...ciItems]
319
319
  break
320
320
  case 'Forecasting':
321
321
  standardLoopItems = [runtime.xAxis.dataKey, ...stageColumns, ...ciItems]