@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
package/src/CdcChart.jsx CHANGED
@@ -1,4 +1,4 @@
1
- import React, { useState, useEffect, useCallback } from 'react'
1
+ import React, { useState, useEffect, useCallback, useRef } from 'react'
2
2
 
3
3
  // IE11
4
4
  import ResizeObserver from 'resize-observer-polyfill'
@@ -9,10 +9,10 @@ import * as d3 from 'd3-array'
9
9
  import { scaleOrdinal } from '@visx/scale'
10
10
  import ParentSize from '@visx/responsive/lib/components/ParentSize'
11
11
  import { timeParse, timeFormat } from 'd3-time-format'
12
- import { format } from 'd3-format'
13
12
  import Papa from 'papaparse'
14
13
  import parse from 'html-react-parser'
15
14
  import 'react-tooltip/dist/react-tooltip.css'
15
+ import chroma from 'chroma-js'
16
16
 
17
17
  // Primary Components
18
18
  import ConfigContext from './ConfigContext'
@@ -27,12 +27,11 @@ import useDataVizClasses from '@cdc/core/helpers/useDataVizClasses'
27
27
 
28
28
  import SparkLine from './components/SparkLine'
29
29
  import Legend from './components/Legend'
30
- import DataTable from './components/DataTable'
31
30
  import defaults from './data/initial-state'
32
31
  import EditorPanel from './components/EditorPanel'
33
32
  import Loading from '@cdc/core/components/Loading'
34
33
  import Filters from '@cdc/core/components/Filters'
35
- import CoveMediaControls from '@cdc/core/components/CoveMediaControls'
34
+ import MediaControls from '@cdc/core/components/MediaControls'
36
35
 
37
36
  // Helpers
38
37
  import numberFromString from '@cdc/core/helpers/numberFromString'
@@ -40,10 +39,44 @@ import getViewport from '@cdc/core/helpers/getViewport'
40
39
  import { DataTransform } from '@cdc/core/helpers/DataTransform'
41
40
  import cacheBustingString from '@cdc/core/helpers/cacheBustingString'
42
41
  import isNumber from '@cdc/core/helpers/isNumber'
42
+ import coveUpdateWorker from '@cdc/core/helpers/coveUpdateWorker'
43
43
 
44
44
  import './scss/main.scss'
45
+ // load both then config below determines which to use
46
+ import DataTable_horiz from './components/DataTable'
47
+ import DataTable_vert from '@cdc/core/components/DataTable'
45
48
 
46
- export default function CdcChart({ configUrl, config: configObj, isEditor = false, isDebug = false, isDashboard = false, setConfig: setParentConfig, setEditing, hostname, link }) {
49
+ const generateColorsArray = (color = '#000000', special = false) => {
50
+ let colorObj = chroma(color)
51
+ let hoverColor = special ? colorObj.brighten(0.5).hex() : colorObj.saturate(1.3).hex()
52
+
53
+ return [color, hoverColor, colorObj.darken(0.3).hex()]
54
+ }
55
+ const hashObj = row => {
56
+ try {
57
+ if (!row) throw new Error('No row supplied to hashObj')
58
+
59
+ let str = JSON.stringify(row)
60
+ let hash = 0
61
+
62
+ if (str.length === 0) return hash
63
+
64
+ for (let i = 0; i < str.length; i++) {
65
+ let char = str.charCodeAt(i)
66
+ hash = (hash << 5) - hash + char
67
+ hash = hash & hash
68
+ }
69
+
70
+ return hash
71
+ } catch (e) {
72
+ console.error('COVE: ', e) // eslint-disable-line
73
+ }
74
+ }
75
+
76
+ // * FILE REVIEW
77
+ // TODO: @tturnerswdev33 - remove/fix mentions of runtimeLegend that were added
78
+
79
+ export default function CdcChart({ configUrl, config: configObj, isEditor = false, isDebug = false, isDashboard = false, setConfig: setParentConfig, setEditing, hostname, link, setSharedFilter, setSharedFilterValue, dashboardConfig }) {
47
80
  const transform = new DataTransform()
48
81
  const [loading, setLoading] = useState(true)
49
82
  const [colorScale, setColorScale] = useState(null)
@@ -60,6 +93,13 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
60
93
  const [dynamicLegendItems, setDynamicLegendItems] = useState([])
61
94
  const [imageId] = useState(`cove-${Math.random().toString(16).slice(-4)}`)
62
95
 
96
+ let legendMemo = useRef(new Map()) // map collection
97
+ let innerContainerRef = useRef()
98
+
99
+ if (isDebug) console.log('Chart config', config)
100
+
101
+ const DataTable = config?.table?.showVertical ? DataTable_vert : DataTable_horiz
102
+
63
103
  // Destructure items from config for more readable JSX
64
104
  let { legend, title, description, visualizationType } = config
65
105
 
@@ -102,26 +142,121 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
102
142
  }
103
143
  }
104
144
 
145
+ const reloadURLData = async () => {
146
+ if (config.dataUrl) {
147
+ const dataUrl = new URL(config.runtimeDataUrl || config.dataUrl)
148
+ let qsParams = Object.fromEntries(new URLSearchParams(dataUrl.search))
149
+
150
+ let isUpdateNeeded = false
151
+ config.filters.forEach(filter => {
152
+ if (filter.type === 'url' && qsParams[filter.queryParameter] !== decodeURIComponent(filter.active)) {
153
+ qsParams[filter.queryParameter] = filter.active
154
+ isUpdateNeeded = true
155
+ }
156
+ })
157
+
158
+ if ((!config.formattedData || config.formattedData.urlFiltered) && !isUpdateNeeded) return
159
+
160
+ let dataUrlFinal = `${dataUrl.origin}${dataUrl.pathname}${Object.keys(qsParams)
161
+ .map((param, i) => {
162
+ let qs = i === 0 ? '?' : '&'
163
+ qs += param + '='
164
+ qs += qsParams[param]
165
+ return qs
166
+ })
167
+ .join('')}`
168
+
169
+ let data
170
+
171
+ try {
172
+ const regex = /(?:\.([^.]+))?$/
173
+
174
+ const ext = regex.exec(dataUrl.pathname)[1]
175
+ if ('csv' === ext) {
176
+ data = await fetch(dataUrlFinal)
177
+ .then(response => response.text())
178
+ .then(responseText => {
179
+ const parsedCsv = Papa.parse(responseText, {
180
+ header: true,
181
+ dynamicTyping: true,
182
+ skipEmptyLines: true
183
+ })
184
+ return parsedCsv.data
185
+ })
186
+ } else if ('json' === ext) {
187
+ data = await fetch(dataUrlFinal).then(response => response.json())
188
+ } else {
189
+ data = []
190
+ }
191
+ } catch {
192
+ console.error(`Cannot parse URL: ${dataUrlFinal}`)
193
+ data = []
194
+ }
195
+
196
+ if (config.dataDescription) {
197
+ data = transform.autoStandardize(data)
198
+ data = transform.developerStandardize(data, config.dataDescription)
199
+ }
200
+
201
+ Object.assign(data, { urlFiltered: true })
202
+
203
+ updateConfig({ ...config, runtimeDataUrl: dataUrlFinal, data, formattedData: data })
204
+
205
+ if (data) {
206
+ setStateData(data)
207
+ setExcludedData(data)
208
+ setFilteredData(filterData(config.filters, data))
209
+ }
210
+ }
211
+ }
212
+
105
213
  const handleLineType = lineType => {
106
214
  switch (lineType) {
107
215
  case 'dashed-sm':
108
216
  return '5 5'
217
+ case 'Dashed Small':
218
+ return '5 5'
109
219
  case 'dashed-md':
110
220
  return '10 5'
221
+ case 'Dashed Medium':
222
+ return '10 5'
111
223
  case 'dashed-lg':
112
224
  return '15 5'
225
+ case 'Dashed Large':
226
+ return '15 5'
113
227
  default:
114
228
  return 0
115
229
  }
116
230
  }
117
231
 
232
+ const lineOptions = [
233
+ {
234
+ value: 'Dashed Small',
235
+ key: 'dashed-sm'
236
+ },
237
+ {
238
+ value: 'Dashed Medium',
239
+ key: 'dashed-md'
240
+ },
241
+ {
242
+ value: 'Dashed Large',
243
+ key: 'dashed-lg'
244
+ },
245
+ {
246
+ value: 'Solid Line',
247
+ key: 'solid-line'
248
+ }
249
+ ]
250
+
118
251
  const loadConfig = async () => {
119
252
  let response = configObj || (await (await fetch(configUrl)).json())
120
253
 
121
254
  // If data is included through a URL, fetch that and store
122
255
  let data = response.formattedData || response.data || {}
123
256
 
124
- if (response.dataUrl) {
257
+ const urlFilters = response.filters ? (response.filters.filter(filter => filter.type === 'url').length > 0 ? true : false) : false
258
+
259
+ if (response.dataUrl && !urlFilters) {
125
260
  try {
126
261
  const regex = /(?:\.([^.]+))?$/
127
262
 
@@ -130,10 +265,20 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
130
265
  data = await fetch(response.dataUrl + `?v=${cacheBustingString()}`)
131
266
  .then(response => response.text())
132
267
  .then(responseText => {
268
+ // for every comma NOT inside quotes, replace with a pipe delimiter
269
+ // - this will let commas inside the quotes not be parsed as a new column
270
+ // - Limitation: if a delimiter other than comma is used in the csv this will break
271
+ // Examples of other delimiters that would break: tab
272
+ responseText = responseText.replace(/(".*?")|,/g, (...m) => m[1] || '|')
273
+ // now strip the double quotes
274
+ responseText = responseText.replace(/["]+/g, '')
133
275
  const parsedCsv = Papa.parse(responseText, {
276
+ //quotes: "true", // dont need these
277
+ //quoteChar: "'", // has no effect that I can tell
134
278
  header: true,
135
279
  dynamicTyping: true,
136
- skipEmptyLines: true
280
+ skipEmptyLines: true,
281
+ delimiter: '|' // we are using pipe symbol as delimiter so setting this explicitly for Papa.parse
137
282
  })
138
283
  return parsedCsv.data
139
284
  })
@@ -158,13 +303,22 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
158
303
  setExcludedData(data)
159
304
  }
160
305
 
306
+ // force showVertical for data tables false if it does not exist
307
+ if (response !== undefined && response.table !== undefined) {
308
+ if (!response.table || !response.table.showVertical) {
309
+ response.table = response.table || {}
310
+ response.table.showVertical = false
311
+ }
312
+ }
161
313
  let newConfig = { ...defaults, ...response }
162
314
  if (newConfig.visualizationType === 'Box Plot') {
163
315
  newConfig.legend.hide = true
164
316
  }
165
317
  if (undefined === newConfig.table.show) newConfig.table.show = !isDashboard
166
318
 
167
- updateConfig(newConfig, data)
319
+ const processedConfig = { ...(await coveUpdateWorker(newConfig)) }
320
+
321
+ updateConfig(processedConfig, data)
168
322
  }
169
323
 
170
324
  const updateConfig = (newConfig, dataOverride = undefined) => {
@@ -177,7 +331,6 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
177
331
  }
178
332
  })
179
333
 
180
- // Loop through and set initial data with exclusions - this should persist through any following data transformations (ie. filters)
181
334
  let newExcludedData
182
335
 
183
336
  if (newConfig.exclusions && newConfig.exclusions.active) {
@@ -219,7 +372,8 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
219
372
 
220
373
  newConfig.filters[index].values = filterValues
221
374
  // Initial filter should be active
222
- newConfig.filters[index].active = filterValues[0]
375
+
376
+ newConfig.filters[index].active = newConfig.filters[index].active || filterValues[0]
223
377
  newConfig.filters[index].filterStyle = newConfig.filters[index].filterStyle ? newConfig.filters[index].filterStyle : 'dropdown'
224
378
  })
225
379
  currentData = filterData(newConfig.filters, newExcludedData)
@@ -373,11 +527,15 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
373
527
  newConfig.runtime.barSeriesKeys = []
374
528
  newConfig.runtime.lineSeriesKeys = []
375
529
  newConfig.runtime.areaSeriesKeys = []
530
+ newConfig.runtime.forecastingSeriesKeys = []
376
531
 
377
532
  newConfig.series.forEach(series => {
378
533
  if (series.type === 'Area Chart') {
379
534
  newConfig.runtime.areaSeriesKeys.push(series)
380
535
  }
536
+ if (series.type === 'Forecasting') {
537
+ newConfig.runtime.forecastingSeriesKeys.push(series)
538
+ }
381
539
  if (series.type === 'Bar') {
382
540
  newConfig.runtime.barSeriesKeys.push(series.dataKey)
383
541
  }
@@ -386,6 +544,17 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
386
544
  }
387
545
  })
388
546
  }
547
+
548
+ if (newConfig.visualizationType === 'Forecasting' && newConfig.series) {
549
+ newConfig.runtime.forecastingSeriesKeys = []
550
+
551
+ newConfig.series.forEach(series => {
552
+ if (series.type === 'Forecasting') {
553
+ newConfig.runtime.forecastingSeriesKeys.push(series)
554
+ }
555
+ })
556
+ }
557
+
389
558
  if (newConfig.visualizationType === 'Area Chart' && newConfig.series) {
390
559
  newConfig.runtime.areaSeriesKeys = []
391
560
 
@@ -416,14 +585,17 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
416
585
 
417
586
  data.forEach(row => {
418
587
  let add = true
419
- filters.forEach(filter => {
420
- if (row[filter.columnName] !== filter.active) {
421
- add = false
422
- }
423
- })
588
+ filters
589
+ .filter(filter => filter.type !== 'url')
590
+ .forEach(filter => {
591
+ if (row[filter.columnName] != filter.active) {
592
+ add = false
593
+ }
594
+ })
424
595
 
425
596
  if (add) filteredData.push(row)
426
597
  })
598
+
427
599
  return filteredData
428
600
  }
429
601
 
@@ -498,6 +670,10 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
498
670
  loadConfig()
499
671
  }, []) // eslint-disable-line
500
672
 
673
+ useEffect(() => {
674
+ reloadURLData()
675
+ }, [JSON.stringify(config.filters)])
676
+
501
677
  /**
502
678
  * When cove has a config and container ref publish the cove_loaded event.
503
679
  */
@@ -594,7 +770,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
594
770
  const newSeriesHighlight = []
595
771
 
596
772
  // If we're highlighting all the series, reset them
597
- if (seriesHighlight.length + 1 === config.runtime.seriesKeys.length && !config.legend.dynamicLegend) {
773
+ if (seriesHighlight.length + 1 === config.runtime.seriesKeys.length && !config.legend.dynamicLegend && config.visualizationType !== 'Forecasting') {
598
774
  highlightReset()
599
775
  return
600
776
  }
@@ -632,10 +808,12 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
632
808
 
633
809
  const section = config.orientation === 'horizontal' ? 'yAxis' : 'xAxis'
634
810
 
635
- const parseDate = dateString => {
811
+ const parseDate = (dateString, showError = true) => {
636
812
  let date = timeParse(config.runtime[section].dateParseFormat)(dateString)
637
813
  if (!date) {
638
- config.runtime.editorErrorMessage = `Error parsing date "${dateString}". Try reviewing your data and date parse settings in the X Axis section.`
814
+ if (showError) {
815
+ config.runtime.editorErrorMessage = `Error parsing date "${dateString}". Try reviewing your data and date parse settings in the X Axis section.`
816
+ }
639
817
  return new Date()
640
818
  } else {
641
819
  return date
@@ -794,6 +972,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
794
972
  // Select appropriate chart type
795
973
  const chartComponents = {
796
974
  'Paired Bar': <LinearChart />,
975
+ Forecasting: <LinearChart />,
797
976
  Bar: <LinearChart />,
798
977
  Line: <LinearChart />,
799
978
  Combo: <LinearChart />,
@@ -805,6 +984,7 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
805
984
  }
806
985
 
807
986
  const missingRequiredSections = () => {
987
+ if (config.visualizationType === 'Forecasting') return false // skip required checks for now.
808
988
  if (config.visualizationType === 'Pie') {
809
989
  if (undefined === config?.yAxis.dataKey) {
810
990
  return true
@@ -822,10 +1002,115 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
822
1002
  return false
823
1003
  }
824
1004
 
1005
+ // used for Additional Column
1006
+ const displayDataAsText = (value, columnName) => {
1007
+ if (value === null || value === '' || value === undefined) {
1008
+ return ''
1009
+ }
1010
+
1011
+ if (typeof value === 'string' && value.length > 0 && config.legend.type === 'equalnumber') {
1012
+ return value
1013
+ }
1014
+
1015
+ let formattedValue = value
1016
+
1017
+ let columnObj //= config.columns[columnName]
1018
+ // config.columns not an array but a hash of objects
1019
+ if (Object.keys(config.columns).length > 0) {
1020
+ Object.keys(config.columns).forEach(function (key) {
1021
+ var column = config.columns[key]
1022
+ // add if not the index AND it is enabled to be added to data table
1023
+ if (column.name === columnName) {
1024
+ columnObj = column
1025
+ }
1026
+ })
1027
+ }
1028
+
1029
+ if (columnObj === undefined) {
1030
+ // then use left axis config
1031
+ columnObj = config.type === 'chart' ? config.dataFormat : config.primary
1032
+ // NOTE: Left Value Axis uses different names
1033
+ // so map them below so the code below works
1034
+ // - copy commas to useCommas to work below
1035
+ columnObj['useCommas'] = columnObj.commas
1036
+ // - copy roundTo to roundToPlace to work below
1037
+ columnObj['roundToPlace'] = columnObj.roundTo ? columnObj.roundTo : ''
1038
+ }
1039
+
1040
+ if (columnObj) {
1041
+ // If value is a number, apply specific formattings
1042
+ let hasDecimal = false
1043
+ let decimalPoint = 0
1044
+ if (Number(value)) {
1045
+ if (columnObj.roundToPlace >= 0) {
1046
+ hasDecimal = columnObj.roundToPlace ? columnObj.roundToPlace !== '' || columnObj.roundToPlace !== null : false
1047
+ decimalPoint = columnObj.roundToPlace ? Number(columnObj.roundToPlace) : 0
1048
+
1049
+ // Rounding
1050
+ if (columnObj.hasOwnProperty('roundToPlace') && hasDecimal) {
1051
+ formattedValue = Number(value).toFixed(decimalPoint)
1052
+ }
1053
+ }
1054
+
1055
+ if (columnObj.hasOwnProperty('useCommas') && columnObj.useCommas === true) {
1056
+ // Formats number to string with commas - allows up to 5 decimal places, if rounding is not defined.
1057
+ // Otherwise, uses the rounding value set at 'columnObj.roundToPlace'.
1058
+ formattedValue = Number(value).toLocaleString('en-US', {
1059
+ style: 'decimal',
1060
+ minimumFractionDigits: hasDecimal ? decimalPoint : 0,
1061
+ maximumFractionDigits: hasDecimal ? decimalPoint : 5
1062
+ })
1063
+ }
1064
+ }
1065
+
1066
+ // add prefix and suffix if set
1067
+ formattedValue = (columnObj.prefix || '') + formattedValue + (columnObj.suffix || '')
1068
+ }
1069
+
1070
+ return formattedValue
1071
+ }
1072
+
1073
+ // this is passed DOWN into the various components
1074
+ // then they do a lookup based on the bin number as index into here (TT)
1075
+ const applyLegendToRow = rowObj => {
1076
+ try {
1077
+ if (!rowObj) throw new Error('COVE: No rowObj in applyLegendToRow')
1078
+ // Navigation map
1079
+ if ('navigation' === config.type) {
1080
+ let mapColorPalette = colorPalettes[config.color] || colorPalettes['bluegreenreverse']
1081
+ return generateColorsArray(mapColorPalette[3])
1082
+ }
1083
+
1084
+ let hash = hashObj(rowObj)
1085
+
1086
+ if (legendMemo.current.has(hash)) {
1087
+ let idx = legendMemo.current.get(hash)
1088
+ if (runtimeLegend[idx]?.disabled) return false
1089
+
1090
+ // DEV-784 changed to use bin prop to get color instead of idx
1091
+ // bc we re-order legend when showSpecialClassesLast is checked
1092
+ let legendBinColor = runtimeLegend.find(o => o.bin === idx)?.color
1093
+ return generateColorsArray(legendBinColor, runtimeLegend[idx]?.special)
1094
+ }
1095
+
1096
+ // Fail state
1097
+ return generateColorsArray()
1098
+ } catch (e) {
1099
+ console.error('COVE: ', e) // eslint-disable-line
1100
+ }
1101
+ }
1102
+
825
1103
  const clean = data => {
1104
+ // cleaning is deleting data we need in forecasting charts.
1105
+ if (config.visualizationType === 'Forecasting') return data
826
1106
  return config?.xAxis?.dataKey ? transform.cleanData(data, config.xAxis.dataKey) : data
827
1107
  }
828
1108
 
1109
+ // required for DataTable
1110
+ const displayGeoName = key => {
1111
+ return key
1112
+ }
1113
+
829
1114
  // Prevent render if loading
830
1115
  let body = <Loading />
831
1116
 
@@ -841,7 +1126,6 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
841
1126
  {!missingRequiredSections() && !config.newViz && (
842
1127
  <div className='cdc-chart-inner-container'>
843
1128
  {/* Title */}
844
-
845
1129
  {title && config.showTitle && (
846
1130
  <div role='heading' className={`chart-title ${config.theme} cove-component__header`} aria-level={2}>
847
1131
  {config && <sup className='superTitle'>{parse(config.superTitle || '')}</sup>}
@@ -886,13 +1170,42 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
886
1170
  {description && config.visualizationType !== 'Spark Line' && <div className='subtext'>{parse(description)}</div>}
887
1171
 
888
1172
  {/* buttons */}
889
- <CoveMediaControls.Section classes={['download-buttons']}>
890
- {config.table.showDownloadImgButton && <CoveMediaControls.Button text='Download Image' title='Download Chart as Image' type='image' state={config} elementToCapture={imageId} />}
891
- {config.table.showDownloadPdfButton && <CoveMediaControls.Button text='Download PDF' title='Download Chart as PDF' type='pdf' state={config} elementToCapture={imageId} />}
892
- </CoveMediaControls.Section>
1173
+ <MediaControls.Section classes={['download-buttons']}>
1174
+ {config.table.showDownloadImgButton && <MediaControls.Button text='Download Image' title='Download Chart as Image' type='image' state={config} elementToCapture={imageId} />}
1175
+ {config.table.showDownloadPdfButton && <MediaControls.Button text='Download PDF' title='Download Chart as PDF' type='pdf' state={config} elementToCapture={imageId} />}
1176
+ </MediaControls.Section>
893
1177
 
894
1178
  {/* Data Table */}
895
- {config.xAxis.dataKey && config.table.show && config.visualizationType !== 'Spark Line' && <DataTable />}
1179
+ {config.xAxis.dataKey && config.table.show && config.visualizationType !== 'Spark Line' && (
1180
+ <DataTable
1181
+ config={config}
1182
+ rawData={config.data}
1183
+ runtimeData={filteredData || excludedData}
1184
+ //navigationHandler={navigationHandler}
1185
+ expandDataTable={config.table.expanded}
1186
+ //headerColor={general.headerColor}
1187
+ columns={config.columns}
1188
+ showDownloadButton={config.general.showDownloadButton}
1189
+ runtimeLegend={dynamicLegendItems}
1190
+ displayDataAsText={displayDataAsText}
1191
+ displayGeoName={displayGeoName}
1192
+ applyLegendToRow={applyLegendToRow}
1193
+ tableTitle={config.table.label}
1194
+ indexTitle={config.table.indexLabel}
1195
+ vizTitle={title}
1196
+ viewport={currentViewport}
1197
+ parseDate={parseDate}
1198
+ formatDate={formatDate}
1199
+ formatNumber={formatNumber}
1200
+ tabbingId={handleChartTabbing}
1201
+ showDownloadImgButton={config.showDownloadImgButton}
1202
+ showDownloadPdfButton={config.showDownloadPdfButton}
1203
+ innerContainerRef={innerContainerRef}
1204
+ outerContainerRef={outerContainerRef}
1205
+ imageRef={imageId}
1206
+ isDebug={isDebug}
1207
+ />
1208
+ )}
896
1209
  {config?.footnotes && <section className='footnotes'>{parse(config.footnotes)}</section>}
897
1210
  {/* show pdf or image button */}
898
1211
  </div>
@@ -939,10 +1252,14 @@ export default function CdcChart({ configUrl, config: configObj, isEditor = fals
939
1252
  filterData,
940
1253
  imageId,
941
1254
  handleLineType,
1255
+ lineOptions,
942
1256
  isNumber,
943
1257
  getTextWidth,
944
1258
  twoColorPalette,
945
- isDebug
1259
+ isDebug,
1260
+ setSharedFilter,
1261
+ setSharedFilterValue,
1262
+ dashboardConfig
946
1263
  }
947
1264
 
948
1265
  const classes = ['cdc-open-viz-module', 'type-chart', `${currentViewport}`, `font-${config.fontSize}`, `${config.theme}`]