@cdc/chart 4.24.9-1 → 4.24.10
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 +37673 -36530
- package/index.html +1 -1
- package/package.json +2 -2
- package/src/CdcChart.tsx +128 -106
- package/src/_stories/Chart.Legend.Gradient.stories.tsx +33 -0
- package/src/_stories/Chart.stories.tsx +28 -0
- package/src/_stories/ChartAxisLabels.stories.tsx +20 -0
- package/src/_stories/ChartAxisTitles.stories.tsx +53 -0
- package/src/_stories/ChartPrefixSuffix.stories.tsx +151 -0
- package/src/_stories/_mock/horizontal_bar.json +257 -0
- package/src/_stories/_mock/large_x_axis_labels.json +261 -0
- package/src/_stories/_mock/paired-bar.json +262 -0
- package/src/_stories/_mock/pie_with_data.json +255 -0
- package/src/_stories/_mock/simplified_line.json +1510 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +0 -3
- package/src/components/Annotations/components/AnnotationDropdown.tsx +1 -1
- package/src/components/Axis/Categorical.Axis.tsx +22 -4
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +95 -16
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +41 -17
- package/src/components/BarChart/components/BarChart.Vertical.tsx +78 -20
- package/src/components/BarChart/helpers/index.ts +23 -4
- package/src/components/BrushChart.tsx +3 -2
- package/src/components/DeviationBar.jsx +58 -8
- package/src/components/EditorPanel/EditorPanel.tsx +62 -39
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +6 -23
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +21 -4
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +297 -35
- package/src/components/EditorPanel/components/panels.scss +4 -6
- package/src/components/EditorPanel/editor-panel.scss +0 -8
- package/src/components/EditorPanel/helpers/tests/updateFieldRankByValue.test.ts +38 -0
- package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +42 -0
- package/src/components/EditorPanel/useEditorPermissions.ts +1 -0
- package/src/components/ForestPlot/ForestPlot.tsx +2 -3
- package/src/components/ForestPlot/ForestPlotProps.ts +2 -0
- package/src/components/Legend/Legend.Component.tsx +16 -16
- package/src/components/Legend/Legend.Suppression.tsx +25 -20
- package/src/components/Legend/Legend.tsx +0 -2
- package/src/components/Legend/helpers/index.ts +16 -19
- package/src/components/LegendWrapper.tsx +3 -1
- package/src/components/LinearChart.tsx +740 -562
- package/src/components/PairedBarChart.jsx +50 -10
- package/src/components/PieChart/PieChart.tsx +1 -6
- package/src/components/Regions/components/Regions.tsx +33 -19
- package/src/components/ZoomBrush.tsx +25 -6
- package/src/coreStyles_chart.scss +3 -0
- package/src/data/initial-state.js +6 -2
- package/src/helpers/configHelpers.ts +28 -0
- package/src/helpers/handleRankByValue.ts +15 -0
- package/src/helpers/sizeHelpers.ts +25 -0
- package/src/helpers/tests/handleRankByValue.test.ts +37 -0
- package/src/helpers/tests/sizeHelpers.test.ts +80 -0
- package/src/hooks/useColorPalette.js +10 -2
- package/src/hooks/useLegendClasses.ts +4 -0
- package/src/hooks/useScales.ts +31 -3
- package/src/hooks/useTooltip.tsx +9 -5
- package/src/index.jsx +1 -0
- package/src/scss/DataTable.scss +5 -4
- package/src/scss/main.scss +57 -52
- package/src/types/ChartConfig.ts +38 -16
- package/src/types/ChartContext.ts +18 -14
- package/src/_stories/Chart.Legend.Gradient.tsx +0 -19
- package/src/_stories/ChartBrush.stories.tsx +0 -19
package/index.html
CHANGED
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
-->
|
|
50
50
|
|
|
51
51
|
<!-- GENERIC CHART TYPES -->
|
|
52
|
-
<div class="react-container" data-config="/examples/cases-year.json"></div>
|
|
52
|
+
<!-- <div class="react-container" data-config="/examples/cases-year.json"></div> -->
|
|
53
53
|
<!-- <div class="react-container" data-config="/examples/test.json"></div> -->
|
|
54
54
|
<!-- <div class="react-container" data-config="/examples/feature/line/line-chart.json"></div> -->
|
|
55
55
|
<!-- <div class="react-container" data-config="/examples/dev-8332.json"></div> -->
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cdc/chart",
|
|
3
|
-
"version": "4.24.
|
|
3
|
+
"version": "4.24.10",
|
|
4
4
|
"description": "React component for visualizing tabular data in various types of charts",
|
|
5
5
|
"moduleName": "CdcChart",
|
|
6
6
|
"main": "dist/cdcchart",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"react": "^18.2.0",
|
|
62
62
|
"react-dom": "^18.2.0"
|
|
63
63
|
},
|
|
64
|
-
"gitHead": "
|
|
64
|
+
"gitHead": "a4d88d1bc91f596e1b0307d8e25c57ad8c668b75",
|
|
65
65
|
"devDependencies": {
|
|
66
66
|
"@types/d3-sankey": "^0.12.4",
|
|
67
67
|
"resize-observer-polyfill": "^1.5.1"
|
package/src/CdcChart.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React, { useState, useEffect, useCallback, useRef, useId } from 'react'
|
|
1
|
+
import React, { useState, useEffect, useCallback, useRef, useId, useMemo } from 'react'
|
|
2
2
|
|
|
3
3
|
// IE11
|
|
4
4
|
import ResizeObserver from 'resize-observer-polyfill'
|
|
@@ -9,6 +9,7 @@ import Button from '@cdc/core/components/elements/Button'
|
|
|
9
9
|
|
|
10
10
|
//types
|
|
11
11
|
import { DimensionsType } from '@cdc/core/types/Dimensions'
|
|
12
|
+
import { type DashboardConfig } from '@cdc/dashboard/src/types/DashboardConfig'
|
|
12
13
|
|
|
13
14
|
// External Libraries
|
|
14
15
|
import { scaleOrdinal } from '@visx/scale'
|
|
@@ -38,6 +39,7 @@ import { sortAsc, sortDesc } from './helpers/sort'
|
|
|
38
39
|
import { handleChartAriaLabels } from './helpers/handleChartAriaLabels'
|
|
39
40
|
import { lineOptions } from './helpers/lineOptions'
|
|
40
41
|
import { handleLineType } from './helpers/handleLineType'
|
|
42
|
+
import { handleRankByValue } from './helpers/handleRankByValue'
|
|
41
43
|
import { generateColorsArray } from './helpers/generateColorsArray'
|
|
42
44
|
import Loading from '@cdc/core/components/Loading'
|
|
43
45
|
import Filters from '@cdc/core/components/Filters'
|
|
@@ -45,7 +47,6 @@ import MediaControls from '@cdc/core/components/MediaControls'
|
|
|
45
47
|
import Annotation from './components/Annotations'
|
|
46
48
|
|
|
47
49
|
// Helpers
|
|
48
|
-
import { getTextWidth } from '@cdc/core/helpers/getTextWidth'
|
|
49
50
|
import { publish, subscribe, unsubscribe } from '@cdc/core/helpers/events'
|
|
50
51
|
import useDataVizClasses from '@cdc/core/helpers/useDataVizClasses'
|
|
51
52
|
import numberFromString from '@cdc/core/helpers/numberFromString'
|
|
@@ -56,6 +57,8 @@ import isNumber from '@cdc/core/helpers/isNumber'
|
|
|
56
57
|
import coveUpdateWorker from '@cdc/core/helpers/coveUpdateWorker'
|
|
57
58
|
import { getQueryStringFilterValue } from '@cdc/core/helpers/queryStringUtils'
|
|
58
59
|
import { isConvertLineToBarGraph } from './helpers/isConvertLineToBarGraph'
|
|
60
|
+
import { calcInitialHeight } from './helpers/sizeHelpers'
|
|
61
|
+
import { isLegendWrapViewport, isMobileHeightViewport } from '@cdc/core/helpers/viewports'
|
|
59
62
|
|
|
60
63
|
import './scss/main.scss'
|
|
61
64
|
// load both then config below determines which to use
|
|
@@ -69,8 +72,24 @@ import { isSolrCsv, isSolrJson } from '@cdc/core/helpers/isSolr'
|
|
|
69
72
|
import SkipTo from '@cdc/core/components/elements/SkipTo'
|
|
70
73
|
import { filterVizData } from '@cdc/core/helpers/filterVizData'
|
|
71
74
|
import LegendWrapper from './components/LegendWrapper'
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
import _ from 'lodash'
|
|
76
|
+
import { addValuesToFilters } from '@cdc/core/helpers/addValuesToFilters'
|
|
77
|
+
|
|
78
|
+
interface CdcChartProps {
|
|
79
|
+
configUrl?: string
|
|
80
|
+
config?: ChartConfig
|
|
81
|
+
isEditor?: boolean
|
|
82
|
+
isDebug?: boolean
|
|
83
|
+
isDashboard?: boolean
|
|
84
|
+
setConfig?: (config: ChartConfig) => void
|
|
85
|
+
setEditing?: (editing: boolean) => void
|
|
86
|
+
hostname?: string
|
|
87
|
+
link?: string
|
|
88
|
+
setSharedFilter?: (filter: any) => void
|
|
89
|
+
setSharedFilterValue?: (value: any) => void
|
|
90
|
+
dashboardConfig?: DashboardConfig
|
|
91
|
+
}
|
|
92
|
+
const CdcChart = ({
|
|
74
93
|
configUrl,
|
|
75
94
|
config: configObj,
|
|
76
95
|
isEditor = false,
|
|
@@ -83,12 +102,13 @@ export default function CdcChart({
|
|
|
83
102
|
setSharedFilter,
|
|
84
103
|
setSharedFilterValue,
|
|
85
104
|
dashboardConfig
|
|
86
|
-
}) {
|
|
105
|
+
}: CdcChartProps) => {
|
|
87
106
|
const transform = new DataTransform()
|
|
88
107
|
const [loading, setLoading] = useState(true)
|
|
108
|
+
const svgRef = useRef(null)
|
|
89
109
|
const [colorScale, setColorScale] = useState(null)
|
|
90
110
|
const [config, setConfig] = useState<ChartConfig>({} as ChartConfig)
|
|
91
|
-
const [stateData, setStateData] = useState(
|
|
111
|
+
const [stateData, setStateData] = useState(_.cloneDeep(configObj?.data) || [])
|
|
92
112
|
const [excludedData, setExcludedData] = useState<Record<string, number>[] | undefined>(undefined)
|
|
93
113
|
const [filteredData, setFilteredData] = useState<Record<string, any>[] | undefined>(undefined)
|
|
94
114
|
const [seriesHighlight, setSeriesHighlight] = useState<string[]>(
|
|
@@ -108,6 +128,7 @@ export default function CdcChart({
|
|
|
108
128
|
isBrushing: false
|
|
109
129
|
})
|
|
110
130
|
|
|
131
|
+
const { description, visualizationType } = config
|
|
111
132
|
let [width] = dimensions
|
|
112
133
|
const useVertical = config.orientation === 'vertical'
|
|
113
134
|
const useMobileVertical = config.heights?.mobileVertical && ['xs', 'xxs'].includes(currentViewport)
|
|
@@ -117,10 +138,8 @@ export default function CdcChart({
|
|
|
117
138
|
if (config.visualizationType === 'Pie') height = config?.heights?.[renderedOrientation]
|
|
118
139
|
height = height + Number(config.orientation === 'horizontal' ? config.yAxis.size : config?.xAxis?.size) + 45
|
|
119
140
|
|
|
120
|
-
type Config = typeof config
|
|
121
|
-
let legendMemo = useRef(new Map()) // map collection
|
|
122
|
-
let innerContainerRef = useRef()
|
|
123
141
|
const legendRef = useRef(null)
|
|
142
|
+
const parentRef = useRef(null)
|
|
124
143
|
|
|
125
144
|
const handleDragStateChange = isDragging => {
|
|
126
145
|
setIsDraggingAnnotation(isDragging)
|
|
@@ -129,7 +148,7 @@ export default function CdcChart({
|
|
|
129
148
|
if (isDebug) console.log('Chart config, isEditor', config, isEditor)
|
|
130
149
|
|
|
131
150
|
// Destructure items from config for more readable JSX
|
|
132
|
-
let { legend, title
|
|
151
|
+
let { legend, title } = config
|
|
133
152
|
|
|
134
153
|
// set defaults on titles if blank AND only in editor
|
|
135
154
|
if (isEditor) {
|
|
@@ -138,7 +157,7 @@ export default function CdcChart({
|
|
|
138
157
|
|
|
139
158
|
if (config.table && (!config.table?.label || config.table?.label === '')) config.table.label = 'Data Table'
|
|
140
159
|
|
|
141
|
-
const {
|
|
160
|
+
const { lineDatapointClass, contentClasses, sparkLineStyles } = useDataVizClasses(config)
|
|
142
161
|
const legendId = useId()
|
|
143
162
|
|
|
144
163
|
const checkLineToBarGraph = () => {
|
|
@@ -201,6 +220,8 @@ export default function CdcChart({
|
|
|
201
220
|
|
|
202
221
|
Object.assign(data, { urlFiltered: true })
|
|
203
222
|
|
|
223
|
+
data = handleRankByValue(data, config)
|
|
224
|
+
|
|
204
225
|
updateConfig({ ...config, runtimeDataUrl: dataUrlFinal, data, formattedData: data })
|
|
205
226
|
|
|
206
227
|
if (data) {
|
|
@@ -212,7 +233,7 @@ export default function CdcChart({
|
|
|
212
233
|
}
|
|
213
234
|
|
|
214
235
|
const loadConfig = async () => {
|
|
215
|
-
|
|
236
|
+
const response = _.cloneDeep(configObj) || (await (await fetch(configUrl)).json())
|
|
216
237
|
|
|
217
238
|
// If data is included through a URL, fetch that and store
|
|
218
239
|
let data: any[] = response.data || []
|
|
@@ -263,6 +284,8 @@ export default function CdcChart({
|
|
|
263
284
|
data = transform.developerStandardize(data, response.dataDescription)
|
|
264
285
|
}
|
|
265
286
|
|
|
287
|
+
data = handleRankByValue(data, response)
|
|
288
|
+
|
|
266
289
|
if (data) {
|
|
267
290
|
setStateData(data)
|
|
268
291
|
setExcludedData(data)
|
|
@@ -276,14 +299,6 @@ export default function CdcChart({
|
|
|
276
299
|
}
|
|
277
300
|
}
|
|
278
301
|
let newConfig = { ...defaults, ...response }
|
|
279
|
-
if (newConfig.filters) {
|
|
280
|
-
newConfig.filters.forEach((filter, index) => {
|
|
281
|
-
const queryStringFilterValue = getQueryStringFilterValue(filter)
|
|
282
|
-
if (queryStringFilterValue) {
|
|
283
|
-
newConfig.filters[index].active = queryStringFilterValue
|
|
284
|
-
}
|
|
285
|
-
})
|
|
286
|
-
}
|
|
287
302
|
|
|
288
303
|
if (newConfig.visualizationType === 'Box Plot') {
|
|
289
304
|
newConfig.legend.hide = true
|
|
@@ -306,9 +321,12 @@ export default function CdcChart({
|
|
|
306
321
|
updateConfig(processedConfig, data)
|
|
307
322
|
}
|
|
308
323
|
|
|
309
|
-
const updateConfig = (
|
|
324
|
+
const updateConfig = (_config, dataOverride?: any[]) => {
|
|
325
|
+
const newConfig = _.cloneDeep(_config)
|
|
310
326
|
let data = dataOverride || stateData
|
|
311
327
|
|
|
328
|
+
data = handleRankByValue(data, newConfig)
|
|
329
|
+
|
|
312
330
|
// Deeper copy
|
|
313
331
|
Object.keys(defaults).forEach(key => {
|
|
314
332
|
if (newConfig[key] && 'object' === typeof newConfig[key] && !Array.isArray(newConfig[key])) {
|
|
@@ -356,28 +374,8 @@ export default function CdcChart({
|
|
|
356
374
|
// After data is grabbed, loop through and generate filter column values if there are any
|
|
357
375
|
let currentData: any[] = []
|
|
358
376
|
if (newConfig.filters) {
|
|
359
|
-
newConfig.filters
|
|
360
|
-
|
|
361
|
-
filter.filterStyle === 'nested-dropdown'
|
|
362
|
-
? filter.values
|
|
363
|
-
: filter.orderedValues ||
|
|
364
|
-
generateValuesForFilter(filter.columnName, newExcludedData).sort(
|
|
365
|
-
filter.order === 'desc' ? sortDesc : sortAsc
|
|
366
|
-
)
|
|
367
|
-
|
|
368
|
-
newConfig.filters[index].values = filterValues
|
|
369
|
-
// Initial filter should be active
|
|
370
|
-
|
|
371
|
-
const includes = (arr: any[], val: any): boolean => (arr || []).map(val => String(val)).includes(String(val))
|
|
372
|
-
newConfig.filters[index].active =
|
|
373
|
-
!newConfig.filters[index].active || !includes(filterValues, newConfig.filters[index].active)
|
|
374
|
-
? filterValues[0]
|
|
375
|
-
: newConfig.filters[index].active
|
|
376
|
-
newConfig.filters[index].filterStyle = newConfig.filters[index].filterStyle
|
|
377
|
-
? newConfig.filters[index].filterStyle
|
|
378
|
-
: 'dropdown'
|
|
379
|
-
})
|
|
380
|
-
currentData = filterVizData(newConfig.filters, newExcludedData)
|
|
377
|
+
const filtersWithValues = addValuesToFilters(newConfig.filters, newExcludedData)
|
|
378
|
+
currentData = filterVizData(filtersWithValues, newExcludedData)
|
|
381
379
|
setFilteredData(currentData)
|
|
382
380
|
}
|
|
383
381
|
|
|
@@ -579,6 +577,7 @@ export default function CdcChart({
|
|
|
579
577
|
) {
|
|
580
578
|
newConfig.runtime.xAxis = newConfig.yAxis['yAxis'] ? newConfig.yAxis['yAxis'] : newConfig.yAxis
|
|
581
579
|
newConfig.runtime.yAxis = newConfig.xAxis['xAxis'] ? newConfig.xAxis['xAxis'] : newConfig.xAxis
|
|
580
|
+
newConfig.runtime.yAxis.labelOffset *= -1
|
|
582
581
|
|
|
583
582
|
newConfig.runtime.horizontal = false
|
|
584
583
|
newConfig.orientation = 'horizontal'
|
|
@@ -654,7 +653,7 @@ export default function CdcChart({
|
|
|
654
653
|
const resizeObserver = new ResizeObserver(entries => {
|
|
655
654
|
for (let entry of entries) {
|
|
656
655
|
let { width, height } = entry.contentRect
|
|
657
|
-
let svgMarginWidth =
|
|
656
|
+
let svgMarginWidth = 30
|
|
658
657
|
let editorWidth = 350
|
|
659
658
|
|
|
660
659
|
width = isEditor ? width - editorWidth : width
|
|
@@ -681,14 +680,14 @@ export default function CdcChart({
|
|
|
681
680
|
setContainer(node)
|
|
682
681
|
}, []) // eslint-disable-line
|
|
683
682
|
|
|
684
|
-
|
|
683
|
+
const isEmpty = obj => {
|
|
685
684
|
return Object.keys(obj).length === 0
|
|
686
685
|
}
|
|
687
686
|
|
|
688
687
|
// Load data when component first mounts
|
|
689
688
|
useEffect(() => {
|
|
690
689
|
loadConfig()
|
|
691
|
-
}, []) // eslint-disable-line
|
|
690
|
+
}, [configObj?.data?.length ? configObj.data : null]) // eslint-disable-line
|
|
692
691
|
|
|
693
692
|
useEffect(() => {
|
|
694
693
|
reloadURLData()
|
|
@@ -752,14 +751,6 @@ export default function CdcChart({
|
|
|
752
751
|
}
|
|
753
752
|
}, [externalFilters]) // eslint-disable-line
|
|
754
753
|
|
|
755
|
-
// Load data when configObj data changes
|
|
756
|
-
if (configObj) {
|
|
757
|
-
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
758
|
-
useEffect(() => {
|
|
759
|
-
loadConfig()
|
|
760
|
-
}, [configObj.data]) // eslint-disable-line
|
|
761
|
-
}
|
|
762
|
-
|
|
763
754
|
// This will set the bump chart's default scaling type to date-time
|
|
764
755
|
useEffect(() => {
|
|
765
756
|
if (['Bump Chart'].includes(config.visualizationType)) {
|
|
@@ -874,8 +865,22 @@ export default function CdcChart({
|
|
|
874
865
|
}
|
|
875
866
|
}
|
|
876
867
|
|
|
877
|
-
const formatDate = date => {
|
|
878
|
-
|
|
868
|
+
const formatDate = (date, prevDate) => {
|
|
869
|
+
let formattedDate = timeFormat(config.runtime[section].dateDisplayFormat)(date)
|
|
870
|
+
// Handle the case where all months work with '%b.' except for May
|
|
871
|
+
if (config.runtime[section].dateDisplayFormat?.includes('%b.') && formattedDate.includes('May.')) {
|
|
872
|
+
formattedDate = formattedDate.replace(/May\./g, 'May')
|
|
873
|
+
}
|
|
874
|
+
// Show years only once
|
|
875
|
+
if (config.xAxis.showYearsOnce && config.runtime[section].dateDisplayFormat?.includes('%Y') && prevDate) {
|
|
876
|
+
const prevFormattedDate = timeFormat(config.runtime[section].dateDisplayFormat)(prevDate)
|
|
877
|
+
const year = formattedDate.match(/\d{4}/)
|
|
878
|
+
const prevYear = prevFormattedDate.match(/\d{4}/)
|
|
879
|
+
if (year && prevYear && year[0] === prevYear[0]) {
|
|
880
|
+
formattedDate = formattedDate.replace(year, '')
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
return formattedDate
|
|
879
884
|
}
|
|
880
885
|
|
|
881
886
|
const formatTooltipsDate = date => {
|
|
@@ -885,7 +890,16 @@ export default function CdcChart({
|
|
|
885
890
|
// Format numeric data based on settings in config OR from passed in settings for Additional Columns
|
|
886
891
|
// - use only for old horizontal data - newer formatNumber is in helper/formatNumber
|
|
887
892
|
// TODO: we should combine various formatNumber functions across this project.
|
|
888
|
-
|
|
893
|
+
// TODO suggestion: pass all options as object key/values to allow for more flexibility
|
|
894
|
+
const formatNumber = (
|
|
895
|
+
num,
|
|
896
|
+
axis,
|
|
897
|
+
shouldAbbreviate = false,
|
|
898
|
+
addColPrefix,
|
|
899
|
+
addColSuffix,
|
|
900
|
+
addColRoundTo,
|
|
901
|
+
{ index, length } = { index: null, length: null }
|
|
902
|
+
) => {
|
|
889
903
|
// if num is NaN return num
|
|
890
904
|
if (isNaN(num) || !num) return num
|
|
891
905
|
// Check if the input number is negative
|
|
@@ -912,7 +926,8 @@ export default function CdcChart({
|
|
|
912
926
|
rightSuffix,
|
|
913
927
|
bottomPrefix,
|
|
914
928
|
bottomSuffix,
|
|
915
|
-
bottomAbbreviated
|
|
929
|
+
bottomAbbreviated,
|
|
930
|
+
onlyShowTopPrefixSuffix
|
|
916
931
|
}
|
|
917
932
|
} = config
|
|
918
933
|
|
|
@@ -1005,7 +1020,9 @@ export default function CdcChart({
|
|
|
1005
1020
|
if (addColPrefix && axis === 'left') {
|
|
1006
1021
|
result = addColPrefix + result
|
|
1007
1022
|
} else {
|
|
1008
|
-
if
|
|
1023
|
+
// if onlyShowTopPrefixSuffix only show top prefix
|
|
1024
|
+
const suppressAllButLast = onlyShowTopPrefixSuffix && length - 1 !== index
|
|
1025
|
+
if (prefix && axis === 'left' && !suppressAllButLast) {
|
|
1009
1026
|
result += prefix
|
|
1010
1027
|
}
|
|
1011
1028
|
}
|
|
@@ -1024,7 +1041,7 @@ export default function CdcChart({
|
|
|
1024
1041
|
if (addColSuffix && axis === 'left') {
|
|
1025
1042
|
result += addColSuffix
|
|
1026
1043
|
} else {
|
|
1027
|
-
if (suffix && axis === 'left') {
|
|
1044
|
+
if (suffix && axis === 'left' && !onlyShowTopPrefixSuffix) {
|
|
1028
1045
|
result += suffix
|
|
1029
1046
|
}
|
|
1030
1047
|
}
|
|
@@ -1234,10 +1251,10 @@ export default function CdcChart({
|
|
|
1234
1251
|
}
|
|
1235
1252
|
|
|
1236
1253
|
const getChartWrapperClasses = () => {
|
|
1237
|
-
const isLegendOnBottom = legend?.position === 'bottom' ||
|
|
1254
|
+
const isLegendOnBottom = legend?.position === 'bottom' || isLegendWrapViewport(currentViewport)
|
|
1238
1255
|
const classes = ['chart-container', 'p-relative']
|
|
1239
1256
|
if (legend?.position) {
|
|
1240
|
-
if (
|
|
1257
|
+
if (isLegendWrapViewport(currentViewport) && legend?.position !== 'top') {
|
|
1241
1258
|
classes.push('legend-bottom')
|
|
1242
1259
|
} else {
|
|
1243
1260
|
classes.push(`legend-${legend.position}`)
|
|
@@ -1254,7 +1271,7 @@ export default function CdcChart({
|
|
|
1254
1271
|
|
|
1255
1272
|
const getChartSubTextClasses = () => {
|
|
1256
1273
|
const classes = ['subtext ']
|
|
1257
|
-
const isLegendOnBottom = legend?.position === 'bottom' ||
|
|
1274
|
+
const isLegendOnBottom = legend?.position === 'bottom' || isLegendWrapViewport(currentViewport)
|
|
1258
1275
|
|
|
1259
1276
|
if (config.isResponsiveTicks) classes.push('subtext--responsive-ticks ')
|
|
1260
1277
|
if (config.brush?.active && !isLegendOnBottom) classes.push('subtext--brush-active ')
|
|
@@ -1290,42 +1307,38 @@ export default function CdcChart({
|
|
|
1290
1307
|
classes={['chart-title', `${config.theme}`, 'cove-component__header']}
|
|
1291
1308
|
style={undefined}
|
|
1292
1309
|
/>
|
|
1293
|
-
{/* Intro Text/Message */}
|
|
1294
|
-
{config?.introText && config.visualizationType !== 'Spark Line' && (
|
|
1295
|
-
<section
|
|
1296
|
-
className={`introText legend_${config.legend.hide ? 'hidden' : 'visible'}_${config.legend.position} `}
|
|
1297
|
-
>
|
|
1298
|
-
{parse(config.introText)}
|
|
1299
|
-
</section>
|
|
1300
|
-
)}
|
|
1301
|
-
|
|
1302
|
-
{/* Filters */}
|
|
1303
|
-
{config.filters && !externalFilters && config.visualizationType !== 'Spark Line' && (
|
|
1304
|
-
<Filters
|
|
1305
|
-
config={config}
|
|
1306
|
-
setConfig={setConfig}
|
|
1307
|
-
setFilteredData={setFilteredData}
|
|
1308
|
-
filteredData={filteredData}
|
|
1309
|
-
excludedData={excludedData}
|
|
1310
|
-
filterData={filterVizData}
|
|
1311
|
-
dimensions={dimensions}
|
|
1312
|
-
/>
|
|
1313
|
-
)}
|
|
1314
|
-
<SkipTo skipId={handleChartTabbing(config, legendId)} skipMessage='Skip Over Chart Container' />
|
|
1315
|
-
{config.annotations?.length > 0 && (
|
|
1316
|
-
<SkipTo
|
|
1317
|
-
skipId={handleChartTabbing(config, legendId)}
|
|
1318
|
-
skipMessage={`Skip over annotations`}
|
|
1319
|
-
key={`skip-annotations`}
|
|
1320
|
-
/>
|
|
1321
|
-
)}
|
|
1322
1310
|
|
|
1323
1311
|
{/* Visualization Wrapper */}
|
|
1324
1312
|
<div className={getChartWrapperClasses().join(' ')}>
|
|
1313
|
+
{/* Intro Text/Message */}
|
|
1314
|
+
{config?.introText && config.visualizationType !== 'Spark Line' && (
|
|
1315
|
+
<section className={`introText `}>{parse(config.introText)}</section>
|
|
1316
|
+
)}
|
|
1317
|
+
|
|
1318
|
+
{/* Filters */}
|
|
1319
|
+
{config.filters && !externalFilters && config.visualizationType !== 'Spark Line' && (
|
|
1320
|
+
<Filters
|
|
1321
|
+
config={config}
|
|
1322
|
+
setConfig={setConfig}
|
|
1323
|
+
setFilteredData={setFilteredData}
|
|
1324
|
+
filteredData={filteredData}
|
|
1325
|
+
excludedData={excludedData}
|
|
1326
|
+
filterData={filterVizData}
|
|
1327
|
+
dimensions={dimensions}
|
|
1328
|
+
/>
|
|
1329
|
+
)}
|
|
1330
|
+
<SkipTo skipId={handleChartTabbing(config, legendId)} skipMessage='Skip Over Chart Container' />
|
|
1331
|
+
{config.annotations?.length > 0 && (
|
|
1332
|
+
<SkipTo
|
|
1333
|
+
skipId={handleChartTabbing(config, legendId)}
|
|
1334
|
+
skipMessage={`Skip over annotations`}
|
|
1335
|
+
key={`skip-annotations`}
|
|
1336
|
+
/>
|
|
1337
|
+
)}
|
|
1325
1338
|
<LegendWrapper>
|
|
1326
1339
|
<div
|
|
1327
1340
|
className={
|
|
1328
|
-
legend.hide ||
|
|
1341
|
+
legend.hide || isLegendWrapViewport(currentViewport)
|
|
1329
1342
|
? 'w-100'
|
|
1330
1343
|
: legend.position === 'bottom' || legend.position === 'top' || visualizationType === 'Sankey'
|
|
1331
1344
|
? 'w-100'
|
|
@@ -1334,30 +1347,36 @@ export default function CdcChart({
|
|
|
1334
1347
|
>
|
|
1335
1348
|
{/* All charts with LinearChart */}
|
|
1336
1349
|
{!['Spark Line', 'Line', 'Sankey', 'Pie', 'Sankey'].includes(config.visualizationType) && (
|
|
1337
|
-
<div style={{
|
|
1350
|
+
<div ref={parentRef} style={{ width: `100%` }}>
|
|
1338
1351
|
<ParentSize>
|
|
1339
|
-
{parent =>
|
|
1352
|
+
{parent => (
|
|
1353
|
+
<LinearChart ref={svgRef} parentWidth={parent.width} parentHeight={parent.height} />
|
|
1354
|
+
)}
|
|
1340
1355
|
</ParentSize>
|
|
1341
1356
|
</div>
|
|
1342
1357
|
)}
|
|
1343
1358
|
|
|
1344
1359
|
{config.visualizationType === 'Pie' && (
|
|
1345
|
-
<ParentSize className='justify-content-center d-flex' style={{
|
|
1346
|
-
{parent => <PieChart parentWidth={parent.width} parentHeight={parent.height} />}
|
|
1360
|
+
<ParentSize className='justify-content-center d-flex' style={{ width: `100%` }}>
|
|
1361
|
+
{parent => <PieChart ref={svgRef} parentWidth={parent.width} parentHeight={parent.height} />}
|
|
1347
1362
|
</ParentSize>
|
|
1348
1363
|
)}
|
|
1349
1364
|
{/* Line Chart */}
|
|
1350
1365
|
{config.visualizationType === 'Line' &&
|
|
1351
1366
|
(checkLineToBarGraph() ? (
|
|
1352
|
-
<div style={{
|
|
1367
|
+
<div ref={parentRef} style={{ width: `100%` }}>
|
|
1353
1368
|
<ParentSize>
|
|
1354
|
-
{parent =>
|
|
1369
|
+
{parent => (
|
|
1370
|
+
<LinearChart ref={svgRef} parentWidth={parent.width} parentHeight={parent.height} />
|
|
1371
|
+
)}
|
|
1355
1372
|
</ParentSize>
|
|
1356
1373
|
</div>
|
|
1357
1374
|
) : (
|
|
1358
|
-
<div style={{
|
|
1375
|
+
<div ref={parentRef} style={{ width: `100%` }}>
|
|
1359
1376
|
<ParentSize>
|
|
1360
|
-
{parent =>
|
|
1377
|
+
{parent => (
|
|
1378
|
+
<LinearChart ref={svgRef} parentWidth={parent.width} parentHeight={parent.height} />
|
|
1379
|
+
)}
|
|
1361
1380
|
</ParentSize>
|
|
1362
1381
|
</div>
|
|
1363
1382
|
))}
|
|
@@ -1411,7 +1430,6 @@ export default function CdcChart({
|
|
|
1411
1430
|
{description && config.visualizationType !== 'Spark Line' && (
|
|
1412
1431
|
<div className={getChartSubTextClasses().join('')}>{parse(description)}</div>
|
|
1413
1432
|
)}
|
|
1414
|
-
{false && <Annotation.List />}
|
|
1415
1433
|
|
|
1416
1434
|
{/* buttons */}
|
|
1417
1435
|
<MediaControls.Section classes={['download-buttons']}>
|
|
@@ -1504,7 +1522,6 @@ export default function CdcChart({
|
|
|
1504
1522
|
formatDate,
|
|
1505
1523
|
formatNumber,
|
|
1506
1524
|
formatTooltipsDate,
|
|
1507
|
-
getTextWidth,
|
|
1508
1525
|
getXAxisData,
|
|
1509
1526
|
getYAxisData,
|
|
1510
1527
|
handleChartAriaLabels,
|
|
@@ -1513,19 +1530,21 @@ export default function CdcChart({
|
|
|
1513
1530
|
highlightReset,
|
|
1514
1531
|
imageId,
|
|
1515
1532
|
isDashboard,
|
|
1516
|
-
isLegendBottom: legend?.position === 'bottom' ||
|
|
1533
|
+
isLegendBottom: legend?.position === 'bottom' || isLegendWrapViewport(currentViewport),
|
|
1517
1534
|
isDebug,
|
|
1518
1535
|
isDraggingAnnotation,
|
|
1519
1536
|
handleDragStateChange,
|
|
1520
1537
|
isEditor,
|
|
1521
1538
|
isNumber,
|
|
1522
1539
|
legend,
|
|
1540
|
+
legendRef,
|
|
1523
1541
|
lineOptions,
|
|
1524
1542
|
loading,
|
|
1525
1543
|
missingRequiredSections,
|
|
1526
1544
|
outerContainerRef,
|
|
1545
|
+
parentRef,
|
|
1527
1546
|
parseDate,
|
|
1528
|
-
rawData: stateData ?? {},
|
|
1547
|
+
rawData: _.cloneDeep(stateData) ?? {},
|
|
1529
1548
|
seriesHighlight,
|
|
1530
1549
|
setBrushConfig,
|
|
1531
1550
|
setConfig,
|
|
@@ -1536,10 +1555,11 @@ export default function CdcChart({
|
|
|
1536
1555
|
setSeriesHighlight,
|
|
1537
1556
|
setSharedFilter,
|
|
1538
1557
|
setSharedFilterValue,
|
|
1558
|
+
svgRef,
|
|
1539
1559
|
tableData: filteredData || excludedData, // do not clean table data
|
|
1540
1560
|
transformedData: clean(filteredData || excludedData), // do this right before passing to components
|
|
1541
1561
|
twoColorPalette,
|
|
1542
|
-
unfilteredData: stateData,
|
|
1562
|
+
unfilteredData: _.cloneDeep(stateData),
|
|
1543
1563
|
updateConfig
|
|
1544
1564
|
}
|
|
1545
1565
|
|
|
@@ -1558,3 +1578,5 @@ export default function CdcChart({
|
|
|
1558
1578
|
</ConfigContext.Provider>
|
|
1559
1579
|
)
|
|
1560
1580
|
}
|
|
1581
|
+
|
|
1582
|
+
export default CdcChart
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import chartGradientConfig from './_mock/legend.gradient_mock.json'
|
|
3
|
+
import SimplifiedLineConfig from './_mock/simplified_line.json'
|
|
4
|
+
|
|
5
|
+
import Chart from '../CdcChart'
|
|
6
|
+
import { editConfigKeys } from '../helpers/configHelpers'
|
|
7
|
+
|
|
8
|
+
const meta: Meta<typeof Chart> = {
|
|
9
|
+
title: 'Components/Templates/Chart/Legend',
|
|
10
|
+
component: Chart
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type Story = StoryObj<typeof Chart>
|
|
14
|
+
|
|
15
|
+
export const Legend_Gradient: Story = {
|
|
16
|
+
args: {
|
|
17
|
+
config: chartGradientConfig
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export const Labels_On_Line_Legend_On_Top: Story = {
|
|
22
|
+
args: {
|
|
23
|
+
config: editConfigKeys(chartGradientConfig, [{ path: ['yAxis', 'labelsAboveGridlines'], value: true }])
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export const Legend_On_Right: Story = {
|
|
28
|
+
args: {
|
|
29
|
+
config: SimplifiedLineConfig
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export default meta
|
|
@@ -5,6 +5,10 @@ import Chart from '../CdcChart'
|
|
|
5
5
|
import lineChartTwoPointsRegressionTest from './_mock/line_chart_two_points_regression_test.json'
|
|
6
6
|
import lineChartTwoPointsNewChart from './_mock/line_chart_two_points_new_chart.json'
|
|
7
7
|
import lollipop from './_mock/lollipop.json'
|
|
8
|
+
import forestPlot from '../../examples/feature/forest-plot/forest-plot.json'
|
|
9
|
+
import pairedBar from './_mock/paired-bar.json'
|
|
10
|
+
import horizontalBarConfig from './_mock/horizontal_bar.json'
|
|
11
|
+
import pieConfig from './_mock/pie_with_data.json'
|
|
8
12
|
|
|
9
13
|
const meta: Meta<typeof Chart> = {
|
|
10
14
|
title: 'Components/Templates/Chart',
|
|
@@ -40,4 +44,28 @@ export const Suppression: Story = {
|
|
|
40
44
|
}
|
|
41
45
|
}
|
|
42
46
|
|
|
47
|
+
export const Forest_Plot: Story = {
|
|
48
|
+
args: {
|
|
49
|
+
config: forestPlot
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export const Horizontal_Bar: Story = {
|
|
54
|
+
args: {
|
|
55
|
+
config: horizontalBarConfig
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const Pie: Story = {
|
|
60
|
+
args: {
|
|
61
|
+
config: pieConfig
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export const Paired_Bar: Story = {
|
|
66
|
+
args: {
|
|
67
|
+
config: pairedBar
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
43
71
|
export default meta
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import SimplifiedLineConfig from './_mock/simplified_line.json'
|
|
3
|
+
|
|
4
|
+
import Chart from '../CdcChart'
|
|
5
|
+
import { editConfigKeys } from '../helpers/configHelpers'
|
|
6
|
+
|
|
7
|
+
const meta: Meta<typeof Chart> = {
|
|
8
|
+
title: 'Components/Templates/Chart/Axis Labels',
|
|
9
|
+
component: Chart
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
type Story = StoryObj<typeof Chart>
|
|
13
|
+
|
|
14
|
+
export const Abbreviated_Dates: Story = {
|
|
15
|
+
args: {
|
|
16
|
+
config: editConfigKeys(SimplifiedLineConfig, [{ path: ['xAxis', 'showYearsOnce'], value: true }])
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export default meta
|