@cdc/chart 4.25.1 → 4.25.3-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 (32) hide show
  1. package/dist/cdcchart.js +40346 -40084
  2. package/examples/feature/tests-non-numerics/example-combo-bar-nonnumeric.json +396 -230
  3. package/examples/private/line-issue.json +497 -0
  4. package/index.html +6 -3
  5. package/package.json +2 -2
  6. package/src/CdcChartComponent.tsx +113 -105
  7. package/src/ConfigContext.tsx +6 -1
  8. package/src/_stories/Chart.DynamicSeries.stories.tsx +16 -1
  9. package/src/_stories/Chart.Filters.stories.tsx +19 -0
  10. package/src/components/Axis/Categorical.Axis.tsx +1 -1
  11. package/src/components/BarChart/components/BarChart.Vertical.tsx +3 -5
  12. package/src/components/BarChart/components/BarChart.jsx +24 -4
  13. package/src/components/BarChart/components/context.tsx +1 -0
  14. package/src/components/BrushChart.tsx +44 -24
  15. package/src/components/DeviationBar.jsx +2 -2
  16. package/src/components/EditorPanel/EditorPanel.tsx +2 -2
  17. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +3 -1
  18. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +6 -1
  19. package/src/components/Legend/helpers/index.ts +10 -4
  20. package/src/components/LineChart/components/LineChart.Circle.tsx +17 -9
  21. package/src/components/LineChart/index.tsx +2 -2
  22. package/src/components/LinearChart.tsx +12 -12
  23. package/src/components/ZoomBrush.tsx +1 -1
  24. package/src/helpers/getColorScale.ts +5 -9
  25. package/src/helpers/isConvertLineToBarGraph.ts +10 -3
  26. package/src/hooks/useBarChart.ts +12 -4
  27. package/src/hooks/useMinMax.ts +7 -8
  28. package/src/hooks/useScales.ts +10 -0
  29. package/src/hooks/useTooltip.tsx +12 -1
  30. package/src/scss/main.scss +1 -1
  31. package/src/store/chart.actions.ts +40 -0
  32. package/src/store/chart.reducer.ts +83 -0
@@ -1,9 +1,10 @@
1
- import React, { useState, useEffect, useCallback, useRef, useId, useContext } from 'react'
1
+ import React, { useState, useEffect, useCallback, useRef, useId, useContext, useReducer } from 'react'
2
2
 
3
3
  // IE11
4
4
  import ResizeObserver from 'resize-observer-polyfill'
5
5
  import 'whatwg-fetch'
6
6
  // Core components
7
+ import fetchRemoteData from '@cdc/core/helpers/fetchRemoteData'
7
8
  import Layout from '@cdc/core/components/Layout'
8
9
  import Confirm from '@cdc/core/components/elements/Confirm'
9
10
  import Error from '@cdc/core/components/elements/Error'
@@ -13,11 +14,9 @@ import DataTable from '@cdc/core/components/DataTable'
13
14
  // Local Components
14
15
  import LegendWrapper from './components/LegendWrapper'
15
16
  //types
16
- import { DimensionsType } from '@cdc/core/types/Dimensions'
17
17
  import { type DashboardConfig } from '@cdc/dashboard/src/types/DashboardConfig'
18
18
  import type { TableConfig } from '@cdc/core/components/DataTable/types/TableConfig'
19
19
  import { AllChartsConfig, ChartConfig } from './types/ChartConfig'
20
- import { type ViewportSize } from './types/ChartConfig'
21
20
  import { Pivot } from '@cdc/core/types/Table'
22
21
  import { Runtime } from '@cdc/core/types/Runtime'
23
22
  import { Label } from './types/Label'
@@ -28,7 +27,7 @@ import parse from 'html-react-parser'
28
27
  import 'react-tooltip/dist/react-tooltip.css'
29
28
  import _ from 'lodash'
30
29
  // Primary Components
31
- import ConfigContext from './ConfigContext'
30
+ import ConfigContext, { ChartDispatchContext } from './ConfigContext'
32
31
  import PieChart from './components/PieChart'
33
32
  import SankeyChart from './components/Sankey'
34
33
  import LinearChart from './components/LinearChart'
@@ -73,6 +72,7 @@ import { getExcludedData } from './helpers/getExcludedData'
73
72
  import { getColorScale } from './helpers/getColorScale'
74
73
  // styles
75
74
  import './scss/main.scss'
75
+ import { getInitialState, reducer } from './store/chart.reducer'
76
76
 
77
77
  interface CdcChartProps {
78
78
  config?: ChartConfig
@@ -100,44 +100,44 @@ const CdcChart: React.FC<CdcChartProps> = ({
100
100
  dashboardConfig
101
101
  }) => {
102
102
  const transform = new DataTransform()
103
- const [loading, setLoading] = useState(true)
103
+ const initialState = getInitialState(configObj)
104
+ const [state, dispatch] = useReducer(reducer, initialState)
105
+ const {
106
+ config,
107
+ stateData,
108
+ excludedData,
109
+ filteredData,
110
+ currentViewport,
111
+ isLoading,
112
+ dimensions,
113
+ container,
114
+ coveLoadedEventRan,
115
+ imageId,
116
+ seriesHighlight,
117
+ colorScale,
118
+ brushConfig
119
+ } = state
120
+ const { description, visualizationType } = config
104
121
  const svgRef = useRef(null)
105
- const [colorScale, setColorScale] = useState(null)
106
- const [config, _setConfig] = useState<ChartConfig>({} as ChartConfig)
107
- const [stateData, setStateData] = useState(_.cloneDeep(configObj?.data) || [])
108
- const [excludedData, setExcludedData] = useState<Record<string, number>[] | undefined>(undefined)
109
- const [filteredData, setFilteredData] = useState<Record<string, any>[] | undefined>(undefined)
110
- const [seriesHighlight, setSeriesHighlight] = useState<string[]>(
111
- configObj && configObj?.legend?.seriesHighlight?.length ? [...configObj?.legend?.seriesHighlight] : []
112
- )
113
- const [currentViewport, setCurrentViewport] = useState<ViewportSize>('lg')
114
- const [dimensions, setDimensions] = useState<DimensionsType>([0, 0])
115
- const [externalFilters, setExternalFilters] = useState<any[]>()
116
- const [container, setContainer] = useState()
117
- const [coveLoadedEventRan, setCoveLoadedEventRan] = useState(false)
118
- const [isDraggingAnnotation, setIsDraggingAnnotation] = useState(false)
119
- const [dynamicLegendItems, setDynamicLegendItems] = useState<any[]>([])
120
- const [imageId] = useState(`cove-${Math.random().toString(16).slice(-4)}`)
121
- const [brushConfig, setBrushConfig] = useState({
122
- data: [],
123
- isActive: false,
124
- isBrushing: false
125
- })
126
122
  const editorContext = useContext(EditorContext)
127
- const setConfig = newConfig => {
128
- _setConfig(newConfig)
123
+ const [externalFilters, setExternalFilters] = useState<any[]>()
124
+
125
+ const setConfig = (newConfig: ChartConfig): void => {
126
+ dispatch({ type: 'SET_CONFIG', payload: newConfig })
129
127
  if (isEditor && !isDashboard) {
130
128
  editorContext.setTempConfig(newConfig)
131
129
  }
132
130
  }
133
131
 
134
- const { description, visualizationType } = config
132
+ const setFiltersData = (filteredData: object[]): void => {
133
+ dispatch({ type: 'SET_FILTERED_DATA', payload: filteredData })
134
+ }
135
135
 
136
136
  const legendRef = useRef(null)
137
137
  const parentRef = useRef(null)
138
138
 
139
139
  const handleDragStateChange = isDragging => {
140
- setIsDraggingAnnotation(isDragging)
140
+ dispatch({ type: 'SET_DRAG_ANNOTATIONS', payload: isDragging })
141
141
  }
142
142
 
143
143
  if (isDebug) console.log('Chart config, isEditor', config, isEditor)
@@ -159,11 +159,9 @@ const CdcChart: React.FC<CdcChartProps> = ({
159
159
  (config.xAxis || config.yAxis) && ['date-time', 'date'].includes((config.xAxis || config.yAxis).type)
160
160
  const dataTableDefaultSortBy = hasDateAxis && config.xAxis.dataKey
161
161
 
162
- const checkLineToBarGraph = () => {
163
- return isConvertLineToBarGraph(config.visualizationType, filteredData, config.allowLineToBarGraph)
164
- }
162
+ const convertLineToBarGraph = isConvertLineToBarGraph(config, filteredData)
165
163
 
166
- const prepareConfig = (loadedConfig: ChartConfig, data): ChartConfig => {
164
+ const prepareConfig = async (loadedConfig: ChartConfig) => {
167
165
  let newConfig = _.defaultsDeep(loadedConfig, defaults)
168
166
  _.defaultsDeep(newConfig, {
169
167
  table: { showVertical: false }
@@ -199,15 +197,14 @@ const CdcChart: React.FC<CdcChartProps> = ({
199
197
  })
200
198
 
201
199
  const newExcludedData: any[] = getExcludedData(newConfig, dataOverride || stateData)
202
-
203
- setExcludedData(newExcludedData)
200
+ dispatch({ type: 'SET_EXCLUDED_DATA', payload: newExcludedData })
204
201
 
205
202
  // After data is grabbed, loop through and generate filter column values if there are any
206
203
  let currentData: any[] = []
207
204
  if (newConfig.filters) {
208
205
  const filtersWithValues = addValuesToFilters(newConfig.filters, newExcludedData)
209
206
  currentData = filterVizData(filtersWithValues, newExcludedData)
210
- setFilteredData(currentData)
207
+ dispatch({ type: 'SET_FILTERED_DATA', payload: currentData })
211
208
  }
212
209
 
213
210
  if (newConfig.xAxis.type === 'date-time' && config.orientation === 'horizontal') {
@@ -297,7 +294,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
297
294
  newConfig.yAxis.type = newConfig.yAxis.type === 'categorical' ? 'linear' : newConfig.yAxis.type
298
295
  } else if (
299
296
  ['Box Plot', 'Scatter Plot', 'Area Chart', 'Line', 'Forecasting'].includes(newConfig.visualizationType) &&
300
- !checkLineToBarGraph()
297
+ !convertLineToBarGraph
301
298
  ) {
302
299
  newConfig.runtime.xAxis = newConfig.xAxis
303
300
  newConfig.runtime.yAxis = newConfig.yAxis
@@ -319,7 +316,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
319
316
  newConfig.runtime.editorErrorMessage = ''
320
317
 
321
318
  if (newConfig.legend.seriesHighlight?.length) {
322
- setSeriesHighlight(newConfig.legend?.seriesHighlight)
319
+ dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: newConfig.legend?.seriesHighlight })
323
320
  }
324
321
 
325
322
  setConfig(newConfig)
@@ -354,15 +351,14 @@ const CdcChart: React.FC<CdcChartProps> = ({
354
351
 
355
352
  const newViewport = getViewport(width)
356
353
 
357
- setCurrentViewport(newViewport)
354
+ dispatch({ type: 'SET_VIEWPORT', payload: newViewport })
358
355
 
359
356
  if (entry.target.dataset.lollipop === 'true') {
360
357
  width = width - 2.5
361
358
  }
362
359
 
363
360
  width = width - svgMarginWidth
364
-
365
- setDimensions([width, height])
361
+ dispatch({ type: 'SET_DIMENSIONS', payload: [width, height] })
366
362
  }
367
363
  })
368
364
 
@@ -370,32 +366,51 @@ const CdcChart: React.FC<CdcChartProps> = ({
370
366
  if (node !== null) {
371
367
  resizeObserver.observe(node)
372
368
  }
373
-
374
- setContainer(node)
369
+ dispatch({ type: 'SET_CONTAINER', payload: node })
375
370
  }, []) // eslint-disable-line
376
371
 
377
- // Load data when component first mounts
372
+ const prepareData = async newConfig => {
373
+ try {
374
+ const urlFilters = newConfig.filters
375
+ ? newConfig.filters.filter(filter => filter.type === 'url').length > 0
376
+ ? true
377
+ : false
378
+ : false
379
+
380
+ if (newConfig.dataUrl && !urlFilters) {
381
+ // handle urls with spaces in the name.
382
+ if (newConfig.dataUrl) newConfig.dataUrl = `${newConfig.dataUrl}`
383
+ let newData = await fetchRemoteData(newConfig.dataUrl, 'Chart')
384
+
385
+ if (newData && newConfig.dataDescription) {
386
+ newData = transform.autoStandardize(newData)
387
+ newData = transform.developerStandardize(newData, newConfig.dataDescription)
388
+ }
378
389
 
379
- const prepareData = (config, data) => {
380
- if (config.dataDescription) {
381
- data = transform.autoStandardize(data)
382
- data = transform.developerStandardize(data, config.dataDescription)
390
+ if (newData) {
391
+ newConfig.data = newData
392
+ }
393
+ } else if (newConfig.formattedData) {
394
+ newConfig.data = newConfig.formattedData
395
+ } else if (newConfig.dataDescription) {
396
+ newConfig.data = transform.autoStandardize(newConfig.data)
397
+ newConfig.data = transform.developerStandardize(newConfig.data, newConfig.dataDescription)
398
+ }
399
+ } catch (err) {
400
+ console.log('Error on prepareData function ', err)
383
401
  }
384
-
385
- data = handleRankByValue(data, config)
386
-
387
- return data
402
+ return newConfig
388
403
  }
404
+
389
405
  useEffect(() => {
390
406
  const load = async () => {
391
407
  try {
392
- const data = configObj.data
393
- if (configObj.data && configObj) {
394
- const preparedConfig = await prepareConfig(configObj, data)
395
- const preparedData = prepareData(configObj, data)
396
- setStateData(preparedData)
397
- setExcludedData(preparedData)
398
- updateConfig(preparedConfig, preparedData)
408
+ if (configObj) {
409
+ const preparedConfig = await prepareConfig(configObj)
410
+ let preppedData = await prepareData(preparedConfig)
411
+ dispatch({ type: 'SET_STATE_DATA', payload: preppedData.data })
412
+ dispatch({ type: 'SET_EXCLUDED_DATA', payload: preppedData.data })
413
+ updateConfig(preparedConfig, preppedData.data)
399
414
  }
400
415
  } catch (err) {
401
416
  console.error('Could not Load!')
@@ -409,11 +424,11 @@ const CdcChart: React.FC<CdcChartProps> = ({
409
424
  * When cove has a config and container ref publish the cove_loaded event.
410
425
  */
411
426
  useEffect(() => {
412
- if (container && !_.isEmpty(config) && !coveLoadedEventRan) {
427
+ if (container && !isLoading && !_.isEmpty(config) && !coveLoadedEventRan) {
413
428
  publish('cove_loaded', { config: config })
414
- setCoveLoadedEventRan(true)
429
+ dispatch({ type: 'SET_LOADED_EVENT', payload: true })
415
430
  }
416
- }, [container, config]) // eslint-disable-line
431
+ }, [container, config, isLoading]) // eslint-disable-line
417
432
 
418
433
  /**
419
434
  * Handles filter change events outside of COVE
@@ -447,7 +462,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
447
462
  let configCopy = { ...config }
448
463
  delete configCopy['filters']
449
464
  setConfig(configCopy)
450
- setFilteredData(filterVizData(externalFilters, excludedData))
465
+ dispatch({ type: 'SET_FILTERED_DATA', payload: filterVizData(externalFilters, excludedData) })
451
466
  }
452
467
  }
453
468
 
@@ -459,7 +474,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
459
474
  ) {
460
475
  let newConfigHere = { ...config, filters: externalFilters }
461
476
  setConfig(newConfigHere)
462
- setFilteredData(filterVizData(externalFilters, excludedData))
477
+ dispatch({ type: 'SET_FILTERED_DATA', payload: filterVizData(externalFilters, excludedData) })
463
478
  }
464
479
  }, [externalFilters]) // eslint-disable-line
465
480
 
@@ -467,9 +482,9 @@ const CdcChart: React.FC<CdcChartProps> = ({
467
482
  useEffect(() => {
468
483
  if (stateData && config.xAxis && config.runtime?.seriesKeys) {
469
484
  const newColorScale = getColorScale(config)
470
-
471
- setColorScale(newColorScale)
472
- setLoading(false)
485
+ dispatch({ type: 'SET_COLOR_SCALE', payload: newColorScale })
486
+ // setColorScale(newColorScale)
487
+ dispatch({ type: 'SET_LOADING', payload: false })
473
488
  }
474
489
 
475
490
  if (config && stateData && config.sortData) {
@@ -486,7 +501,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
486
501
  const newHighlight = _.findKey(config.runtime.seriesLabels, v => v === label.datum) || label.datum
487
502
 
488
503
  const newSeriesHighlight = _.xor(seriesHighlight, [newHighlight])
489
- setSeriesHighlight(newSeriesHighlight)
504
+ dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: newSeriesHighlight })
490
505
  }
491
506
  // Called on reset button click, unhighlights all data series
492
507
  const handleShowAll = () => {
@@ -497,7 +512,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
497
512
  } catch (e) {
498
513
  console.error('COVE:', e.message)
499
514
  }
500
- setSeriesHighlight([])
515
+ dispatch({ type: 'SET_SERIES_HIGHLIGHT', payload: [] })
501
516
  }
502
517
 
503
518
  const section = config.orientation === 'horizontal' ? 'yAxis' : 'xAxis'
@@ -733,8 +748,13 @@ const CdcChart: React.FC<CdcChartProps> = ({
733
748
  // cleaning is deleting data we need in forecasting charts.
734
749
  if (!Array.isArray(data)) return []
735
750
  if (config.visualizationType === 'Forecasting') return data
736
- if (config.series?.some(series => !!series.dynamicCategory)) return data
737
- return config?.xAxis?.dataKey ? transform.cleanData(data, config.xAxis.dataKey) : data
751
+ // specify keys that needs to be cleaned to render chart and skip rest
752
+ const CIkeys: string[] = Object.values(config.confidenceKeys) as string[]
753
+ const seriesKeys: string[] = config.series.map(s => s.dataKey)
754
+ const keysToClean: string[] = seriesKeys.concat(CIkeys)
755
+ // key that does not need to be cleaned
756
+ const excludedKey = config.xAxis.dataKey
757
+ return config?.xAxis?.dataKey ? transform.cleanData(data, excludedKey, keysToClean) : data
738
758
  }
739
759
 
740
760
  const getTableRuntimeData = () => {
@@ -797,7 +817,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
797
817
  return classes
798
818
  }
799
819
 
800
- if (!loading) {
820
+ if (!isLoading) {
801
821
  const tableLink = (
802
822
  <a href={`#data-table-${config.dataKey}`} className='margin-left-href'>
803
823
  {config.dataKey} (Go to Table)
@@ -841,7 +861,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
841
861
  <Filters
842
862
  config={config}
843
863
  setConfig={setConfig}
844
- setFilteredData={setFilteredData}
864
+ setFilteredData={setFiltersData}
845
865
  filteredData={filteredData}
846
866
  excludedData={excludedData}
847
867
  filterData={filterVizData}
@@ -884,7 +904,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
884
904
  )}
885
905
  {/* Line Chart */}
886
906
  {config.visualizationType === 'Line' &&
887
- (checkLineToBarGraph() ? (
907
+ (convertLineToBarGraph ? (
888
908
  <div ref={parentRef} style={{ width: `100%` }}>
889
909
  <ParentSize>
890
910
  {parent => (
@@ -907,7 +927,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
907
927
  <Filters
908
928
  config={config}
909
929
  setConfig={setConfig}
910
- setFilteredData={setFilteredData}
930
+ setFilteredData={setFiltersData}
911
931
  filteredData={filteredData}
912
932
  excludedData={excludedData}
913
933
  filterData={filterVizData}
@@ -949,9 +969,7 @@ const CdcChart: React.FC<CdcChartProps> = ({
949
969
  {/* Description */}
950
970
 
951
971
  {config.description && config.visualizationType !== 'Spark Line' && (
952
- <div className={getChartSubTextClasses(config, currentViewport, isLegendWrapViewport).join(' ')}>
953
- {parse(config.description)}
954
- </div>
972
+ <div className={getChartSubTextClasses().join(' ')}>{parse(config.description)}</div>
955
973
  )}
956
974
 
957
975
  {/* buttons */}
@@ -1029,18 +1047,14 @@ const CdcChart: React.FC<CdcChartProps> = ({
1029
1047
  }
1030
1048
 
1031
1049
  const contextValues = {
1050
+ ...state,
1032
1051
  brushConfig,
1033
1052
  capitalize,
1053
+ convertLineToBarGraph,
1034
1054
  clean,
1035
1055
  colorPalettes,
1036
- colorScale,
1037
- config,
1038
- currentViewport,
1039
1056
  dashboardConfig,
1040
1057
  debugSvg: isDebug,
1041
- dimensions,
1042
- dynamicLegendItems,
1043
- excludedData,
1044
1058
  formatDate,
1045
1059
  formatNumber,
1046
1060
  formatTooltipsDate,
@@ -1051,10 +1065,8 @@ const CdcChart: React.FC<CdcChartProps> = ({
1051
1065
  handleChartTabbing,
1052
1066
  highlight,
1053
1067
  handleShowAll,
1054
- imageId,
1055
1068
  isDashboard,
1056
1069
  isDebug,
1057
- isDraggingAnnotation,
1058
1070
  handleDragStateChange,
1059
1071
  isEditor,
1060
1072
  isNumber,
@@ -1062,25 +1074,19 @@ const CdcChart: React.FC<CdcChartProps> = ({
1062
1074
  legendId,
1063
1075
  legendRef,
1064
1076
  lineOptions,
1065
- loading,
1066
1077
  missingRequiredSections,
1067
1078
  outerContainerRef,
1068
1079
  parentRef,
1069
1080
  parseDate,
1070
1081
  rawData: _.cloneDeep(stateData) ?? {},
1071
- seriesHighlight,
1072
- setBrushConfig,
1073
1082
  setConfig,
1074
- setDynamicLegendItems,
1075
1083
  setEditing,
1076
- setFilteredData,
1077
1084
  setParentConfig,
1078
- setSeriesHighlight,
1079
1085
  setSharedFilter,
1080
1086
  setSharedFilterValue,
1081
1087
  svgRef,
1082
- tableData: filteredData || excludedData, // do not clean table data
1083
- transformedData: clean(filteredData || excludedData), // do this right before passing to components
1088
+ tableData: filteredData || excludedData,
1089
+ transformedData: clean(filteredData || excludedData),
1084
1090
  twoColorPalette,
1085
1091
  unfilteredData: _.cloneDeep(stateData),
1086
1092
  updateConfig
@@ -1088,16 +1094,18 @@ const CdcChart: React.FC<CdcChartProps> = ({
1088
1094
 
1089
1095
  return (
1090
1096
  <ConfigContext.Provider value={contextValues}>
1091
- <Layout.VisualizationWrapper
1092
- config={config}
1093
- isEditor={isEditor}
1094
- currentViewport={currentViewport}
1095
- ref={outerContainerRef}
1096
- imageId={imageId}
1097
- showEditorPanel={config?.showEditorPanel}
1098
- >
1099
- {body}
1100
- </Layout.VisualizationWrapper>
1097
+ <ChartDispatchContext.Provider value={dispatch}>
1098
+ <Layout.VisualizationWrapper
1099
+ config={config}
1100
+ isEditor={isEditor}
1101
+ currentViewport={currentViewport}
1102
+ ref={outerContainerRef}
1103
+ imageId={imageId}
1104
+ showEditorPanel={config?.showEditorPanel}
1105
+ >
1106
+ {body}
1107
+ </Layout.VisualizationWrapper>
1108
+ </ChartDispatchContext.Provider>
1101
1109
  </ConfigContext.Provider>
1102
1110
  )
1103
1111
  }
@@ -1,6 +1,11 @@
1
- import { createContext } from 'react'
1
+ import { createContext, Dispatch } from 'react'
2
2
  import { ChartContext } from './types/ChartContext'
3
3
 
4
+ import ChartActions from './store/chart.actions'
5
+
6
+ // export const ConfigContext = createContext(initialState)
7
+ export const ChartDispatchContext = createContext<Dispatch<ChartActions>>(() => {})
8
+
4
9
  const ConfigContext = createContext({} as ChartContext)
5
10
 
6
11
  export default ConfigContext
@@ -10,7 +10,22 @@ const meta: Meta<typeof Chart> = {
10
10
 
11
11
  type Story = StoryObj<typeof Chart>
12
12
 
13
- export const Line: Story = {
13
+ // data with a line break
14
+ const data = DynamicSeriesConfig.data.map((d, i) => (i === 4 ? { ...d, Data_Value: null } : d))
15
+ export const LineShowPoints: Story = {
16
+ args: {
17
+ config: {
18
+ ...DynamicSeriesConfig,
19
+ data,
20
+ originalFormattedData: data,
21
+ formattedData: data,
22
+ lineDatapointStyle: 'always show'
23
+ },
24
+ isEditor: false
25
+ }
26
+ }
27
+
28
+ export const LineHoverPoints: Story = {
14
29
  args: {
15
30
  config: DynamicSeriesConfig,
16
31
  isEditor: false
@@ -0,0 +1,19 @@
1
+ import type { Meta, StoryObj } from '@storybook/react'
2
+ import Chart from '../CdcChartComponent'
3
+ import { editConfigKeys } from '../helpers/configHelpers'
4
+ import scatterPlotDownloadImage from './_mock/scatterplot-image-download.json'
5
+
6
+ const meta: Meta<typeof Chart> = {
7
+ title: 'Components/Templates/Chart/Filters',
8
+ component: Chart
9
+ }
10
+
11
+ type Story = StoryObj<typeof Chart>
12
+
13
+ export const Tab_Simple: Story = {
14
+ args: {
15
+ config: editConfigKeys(scatterPlotDownloadImage, [{ path: ['filters', '0', 'filterStyle'], value: 'tab-simple' }])
16
+ }
17
+ }
18
+
19
+ export default meta
@@ -96,7 +96,7 @@ const CategoricalYAxis = ({ yMax, leftSize, max, xMax }) => {
96
96
  const isLastIndex = config.yAxis.categories.length - 1 === barStack.index
97
97
  const textSize = appFontSize / 1.3
98
98
  const textColor = chroma(bar.color).luminance() < 0.4 ? '#fff' : '#000'
99
- const textWidth = getTextWidth(bar.key)
99
+ const textWidth = getTextWidth(bar.key, `${textSize}px`)
100
100
  const displayText = Number(textWidth) < bar.width && bar.height > textSize
101
101
  const tooltip = `<ul>
102
102
  <li class="tooltip-heading""> Label : ${bar.key} </li>
@@ -6,7 +6,6 @@ import BarChartContext, { type BarChartContextValues } from './context'
6
6
  import { useBarChart } from '../../../hooks/useBarChart'
7
7
  import { useHighlightedBars } from '../../../hooks/useHighlightedBars'
8
8
  import { getBarConfig, testZeroValue } from '../helpers'
9
- import { isConvertLineToBarGraph } from '../../../helpers/isConvertLineToBarGraph'
10
9
  // VisX library imports
11
10
  import { Group } from '@visx/group'
12
11
  import { Text } from '@visx/text'
@@ -25,7 +24,8 @@ import _ from 'lodash'
25
24
  import { getBarData } from '../helpers/getBarData'
26
25
 
27
26
  export const BarChartVertical = () => {
28
- const { xScale, yScale, xMax, yMax, seriesScale } = useContext<BarChartContextValues>(BarChartContext)
27
+ const { xScale, yScale, xMax, yMax, seriesScale, convertLineToBarGraph } =
28
+ useContext<BarChartContextValues>(BarChartContext)
29
29
 
30
30
  const [barWidth, setBarWidth] = useState(0)
31
31
  const [totalBarsInGroup, setTotalBarsInGroup] = useState(0)
@@ -70,9 +70,7 @@ export const BarChartVertical = () => {
70
70
  const _data = getBarData(config, data, hasConfidenceInterval)
71
71
  return (
72
72
  config.visualizationSubType !== 'stacked' &&
73
- (config.visualizationType === 'Bar' ||
74
- config.visualizationType === 'Combo' ||
75
- isConvertLineToBarGraph(config.visualizationType, data, config.allowLineToBarGraph)) &&
73
+ (config.visualizationType === 'Bar' || config.visualizationType === 'Combo' || convertLineToBarGraph) &&
76
74
  config.orientation === 'vertical' && (
77
75
  <Group>
78
76
  <BarGroup
@@ -10,15 +10,25 @@ import ErrorBoundary from '@cdc/core/components/ErrorBoundary'
10
10
  import ConfigContext from '../../../ConfigContext'
11
11
  import BarChartContext from './context'
12
12
 
13
- const BarChart = ({ xScale, yScale, seriesScale, xMax, yMax, handleTooltipMouseOver, handleTooltipMouseOff, handleTooltipClick }) => {
14
- const { transformedData: data, config } = useContext(ConfigContext)
13
+ const BarChart = ({
14
+ xScale,
15
+ yScale,
16
+ seriesScale,
17
+ xMax,
18
+ yMax,
19
+ handleTooltipMouseOver,
20
+ handleTooltipMouseOff,
21
+ handleTooltipClick
22
+ }) => {
23
+ const { transformedData: data, config, convertLineToBarGraph } = useContext(ConfigContext)
15
24
 
16
25
  const contextValues = {
17
26
  xScale,
18
27
  yScale,
19
28
  xMax,
20
29
  yMax,
21
- seriesScale
30
+ seriesScale,
31
+ convertLineToBarGraph
22
32
  }
23
33
 
24
34
  return (
@@ -29,7 +39,17 @@ const BarChart = ({ xScale, yScale, seriesScale, xMax, yMax, handleTooltipMouseO
29
39
  <BarChartType.StackedHorizontal />
30
40
  <BarChartType.Vertical />
31
41
  <BarChartType.Horizontal />
32
- <Bar key={'bars'} display={config.tooltips.singleSeries ? 'none' : 'block'} width={Number(xMax)} height={Number(yMax)} fill={'transparent'} fillOpacity={0.05} onMouseMove={e => handleTooltipMouseOver(e, data)} onMouseOut={handleTooltipMouseOff} onClick={e => handleTooltipClick(e, data)} />
42
+ <Bar
43
+ key={'bars'}
44
+ display={config.tooltips.singleSeries ? 'none' : 'block'}
45
+ width={Number(xMax)}
46
+ height={Number(yMax)}
47
+ fill={'transparent'}
48
+ fillOpacity={0.05}
49
+ onMouseMove={e => handleTooltipMouseOver(e, data)}
50
+ onMouseOut={handleTooltipMouseOff}
51
+ onClick={e => handleTooltipClick(e, data)}
52
+ />
33
53
  </Group>
34
54
  </BarChartContext.Provider>
35
55
  </ErrorBoundary>
@@ -8,6 +8,7 @@ export type BarChartContextValues = {
8
8
  xScale: Function
9
9
  yScale: Function
10
10
  seriesScale: Function
11
+ convertLineToBarGraph: boolean
11
12
  }
12
13
 
13
14
  export default BarChartContext