@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.
- package/dist/cdcchart.js +40346 -40084
- package/examples/feature/tests-non-numerics/example-combo-bar-nonnumeric.json +396 -230
- package/examples/private/line-issue.json +497 -0
- package/index.html +6 -3
- package/package.json +2 -2
- package/src/CdcChartComponent.tsx +113 -105
- package/src/ConfigContext.tsx +6 -1
- package/src/_stories/Chart.DynamicSeries.stories.tsx +16 -1
- package/src/_stories/Chart.Filters.stories.tsx +19 -0
- package/src/components/Axis/Categorical.Axis.tsx +1 -1
- package/src/components/BarChart/components/BarChart.Vertical.tsx +3 -5
- package/src/components/BarChart/components/BarChart.jsx +24 -4
- package/src/components/BarChart/components/context.tsx +1 -0
- package/src/components/BrushChart.tsx +44 -24
- package/src/components/DeviationBar.jsx +2 -2
- package/src/components/EditorPanel/EditorPanel.tsx +2 -2
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +3 -1
- package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +6 -1
- package/src/components/Legend/helpers/index.ts +10 -4
- package/src/components/LineChart/components/LineChart.Circle.tsx +17 -9
- package/src/components/LineChart/index.tsx +2 -2
- package/src/components/LinearChart.tsx +12 -12
- package/src/components/ZoomBrush.tsx +1 -1
- package/src/helpers/getColorScale.ts +5 -9
- package/src/helpers/isConvertLineToBarGraph.ts +10 -3
- package/src/hooks/useBarChart.ts +12 -4
- package/src/hooks/useMinMax.ts +7 -8
- package/src/hooks/useScales.ts +10 -0
- package/src/hooks/useTooltip.tsx +12 -1
- package/src/scss/main.scss +1 -1
- package/src/store/chart.actions.ts +40 -0
- 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
|
|
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
|
|
128
|
-
|
|
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
|
|
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
|
-
|
|
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
|
|
163
|
-
return isConvertLineToBarGraph(config.visualizationType, filteredData, config.allowLineToBarGraph)
|
|
164
|
-
}
|
|
162
|
+
const convertLineToBarGraph = isConvertLineToBarGraph(config, filteredData)
|
|
165
163
|
|
|
166
|
-
const prepareConfig = (loadedConfig: 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
|
-
|
|
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
|
-
!
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
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
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
737
|
-
|
|
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 (!
|
|
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={
|
|
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
|
-
(
|
|
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={
|
|
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(
|
|
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,
|
|
1083
|
-
transformedData: clean(filteredData || excludedData),
|
|
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
|
-
<
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
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
|
}
|
package/src/ConfigContext.tsx
CHANGED
|
@@ -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
|
-
|
|
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 } =
|
|
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 = ({
|
|
14
|
-
|
|
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
|
|
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>
|