@cdc/chart 4.24.12 → 4.25.2-25
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 +79900 -78999
- package/examples/feature/boxplot/boxplot.json +2 -157
- package/examples/feature/boxplot/testing.csv +23 -38
- package/examples/feature/tests-non-numerics/example-combo-bar-nonnumeric.json +579 -49
- package/examples/private/ehdi.json +29939 -0
- package/examples/private/line-issue.json +497 -0
- package/examples/private/not-loading.json +360 -0
- package/index.html +11 -15
- package/package.json +2 -2
- package/src/CdcChart.tsx +92 -1512
- package/src/CdcChartComponent.tsx +1113 -0
- package/src/ConfigContext.tsx +6 -1
- package/src/_stories/Chart.Anchors.stories.tsx +1 -1
- package/src/_stories/Chart.CustomColors.stories.tsx +1 -1
- package/src/_stories/Chart.DynamicSeries.stories.tsx +17 -2
- package/src/_stories/Chart.Filters.stories.tsx +19 -0
- package/src/_stories/Chart.Legend.Gradient.stories.tsx +2 -2
- package/src/_stories/Chart.ScatterPlot.stories.tsx +19 -0
- package/src/_stories/Chart.tooltip.stories.tsx +1 -2
- package/src/_stories/ChartAnnotation.stories.tsx +1 -1
- package/src/_stories/ChartAxisLabels.stories.tsx +1 -1
- package/src/_stories/ChartAxisTitles.stories.tsx +1 -1
- package/src/_stories/ChartEditor.stories.tsx +1 -1
- package/src/_stories/ChartLine.Suppression.stories.tsx +1 -1
- package/src/_stories/ChartLine.Symbols.stories.tsx +18 -0
- package/src/_stories/ChartPrefixSuffix.stories.tsx +1 -1
- package/src/_stories/_mock/line_chart_symbols.json +437 -0
- package/src/_stories/_mock/scatterplot-image-download.json +1244 -0
- package/src/components/Annotations/components/AnnotationDraggable.tsx +3 -11
- package/src/components/Annotations/components/AnnotationDropdown.tsx +3 -3
- package/src/components/Axis/Categorical.Axis.tsx +3 -4
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +14 -5
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +10 -4
- package/src/components/BarChart/components/BarChart.Vertical.tsx +5 -7
- package/src/components/BarChart/components/BarChart.jsx +24 -4
- package/src/components/BarChart/components/context.tsx +1 -0
- package/src/components/BoxPlot/BoxPlot.tsx +34 -32
- package/src/components/BoxPlot/helpers/index.ts +108 -18
- package/src/components/BrushChart.tsx +44 -24
- package/src/components/DeviationBar.jsx +2 -6
- package/src/components/EditorPanel/EditorPanel.tsx +64 -8
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +4 -0
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +3 -1
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +44 -7
- package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +6 -1
- package/src/components/ForestPlot/ForestPlot.tsx +176 -26
- package/src/components/Legend/Legend.Component.tsx +29 -38
- package/src/components/Legend/Legend.Suppression.tsx +3 -5
- package/src/components/Legend/Legend.tsx +2 -2
- package/src/components/Legend/LegendLine.Shape.tsx +51 -0
- package/src/components/Legend/helpers/createFormatLabels.tsx +29 -26
- package/src/components/Legend/helpers/getLegendClasses.ts +20 -38
- package/src/components/Legend/helpers/index.ts +22 -9
- package/src/components/Legend/tests/getLegendClasses.test.ts +3 -20
- package/src/components/LineChart/components/LineChart.Circle.tsx +104 -94
- package/src/components/LineChart/index.tsx +6 -2
- package/src/components/LinearChart.tsx +77 -43
- package/src/components/PairedBarChart.jsx +2 -9
- package/src/components/ZoomBrush.tsx +5 -7
- package/src/data/initial-state.js +6 -3
- package/src/helpers/getBoxPlotConfig.ts +68 -0
- package/src/helpers/getColorScale.ts +24 -0
- package/src/helpers/getComboChartConfig.ts +42 -0
- package/src/helpers/getExcludedData.ts +37 -0
- package/src/helpers/getTopAxis.ts +7 -0
- package/src/helpers/isConvertLineToBarGraph.ts +10 -3
- package/src/hooks/useBarChart.ts +40 -13
- package/src/hooks/{useHighlightedBars.js → useHighlightedBars.ts} +2 -1
- package/src/hooks/useIntersectionObserver.ts +37 -0
- package/src/hooks/useMinMax.ts +11 -8
- package/src/hooks/useReduceData.ts +1 -1
- package/src/hooks/useScales.ts +10 -0
- package/src/hooks/useTooltip.tsx +21 -2
- package/src/index.jsx +1 -0
- package/src/scss/DataTable.scss +0 -5
- package/src/scss/main.scss +31 -116
- package/src/store/chart.actions.ts +40 -0
- package/src/store/chart.reducer.ts +83 -0
- package/src/types/ChartConfig.ts +6 -3
- package/src/types/ChartContext.ts +1 -3
- package/src/helpers/getQuartiles.ts +0 -27
- package/src/hooks/useColorScale.ts +0 -50
- package/src/hooks/useIntersectionObserver.jsx +0 -29
- package/src/hooks/useTopAxis.js +0 -6
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { DimensionsType } from '@cdc/core/types/Dimensions'
|
|
2
|
+
import { ChartConfig } from '../types/ChartConfig'
|
|
3
|
+
|
|
4
|
+
type Action<T, P = undefined, R = undefined> = {
|
|
5
|
+
type: T
|
|
6
|
+
payload?: P
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
// Action Types
|
|
10
|
+
type SET_CONFIG = Action<'SET_CONFIG', ChartConfig>
|
|
11
|
+
type SET_LOADING = Action<'SET_LOADING', boolean>
|
|
12
|
+
type UPDATE_CONFIG = Action<'UPDATE_CONFIG', ChartConfig>
|
|
13
|
+
type SET_COLOR_SCALE = Action<'SET_COLOR_SCALE', Function>
|
|
14
|
+
type SET_STATE_DATA = Action<'SET_STATE_DATA', object[]>
|
|
15
|
+
type SET_EXCLUDED_DATA = Action<'SET_EXCLUDED_DATA', object[]>
|
|
16
|
+
type SET_FILTERED_DATA = Action<'SET_FILTERED_DATA', object[]>
|
|
17
|
+
type SET_SERIES_HIGHLIGHT = Action<'SET_SERIES_HIGHLIGHT', object>
|
|
18
|
+
type SET_VIEWPORT = Action<'SET_VIEWPORT', string>
|
|
19
|
+
type SET_DIMENSIONS = Action<'SET_DIMENSIONS', DimensionsType>
|
|
20
|
+
type SET_CONTAINER = Action<'SET_CONTAINER', object>
|
|
21
|
+
type SET_LOADED_EVENT = Action<'SET_LOADED_EVENT', boolean>
|
|
22
|
+
type SET_DRAG_ANNOTATIONS = Action<'SET_DRAG_ANNOTATIONS', boolean>
|
|
23
|
+
type SET_BRUSH_CONFIG = Action<'SET_BRUSH_CONFIG', object>
|
|
24
|
+
type ChartActions =
|
|
25
|
+
| SET_CONFIG
|
|
26
|
+
| UPDATE_CONFIG
|
|
27
|
+
| SET_COLOR_SCALE
|
|
28
|
+
| SET_STATE_DATA
|
|
29
|
+
| SET_EXCLUDED_DATA
|
|
30
|
+
| SET_FILTERED_DATA
|
|
31
|
+
| SET_SERIES_HIGHLIGHT
|
|
32
|
+
| SET_VIEWPORT
|
|
33
|
+
| SET_DIMENSIONS
|
|
34
|
+
| SET_CONTAINER
|
|
35
|
+
| SET_LOADED_EVENT
|
|
36
|
+
| SET_DRAG_ANNOTATIONS
|
|
37
|
+
| SET_BRUSH_CONFIG
|
|
38
|
+
| SET_LOADING
|
|
39
|
+
|
|
40
|
+
export default ChartActions
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import ChartActions from './chart.actions'
|
|
2
|
+
import defaults from '../data/initial-state.js'
|
|
3
|
+
import { ChartConfig, type ViewportSize } from '../types/ChartConfig'
|
|
4
|
+
import { DimensionsType } from '@cdc/core/types/Dimensions'
|
|
5
|
+
import _ from 'lodash'
|
|
6
|
+
|
|
7
|
+
export const getInitialState = (configObj: ChartConfig) => {
|
|
8
|
+
return {
|
|
9
|
+
isLoading: true,
|
|
10
|
+
config: defaults,
|
|
11
|
+
stateData: _.cloneDeep(configObj?.data) || [],
|
|
12
|
+
colorScale: null,
|
|
13
|
+
excludedData: undefined,
|
|
14
|
+
filteredData: undefined,
|
|
15
|
+
seriesHighlight:
|
|
16
|
+
configObj && configObj?.legend?.seriesHighlight?.length ? [...configObj?.legend?.seriesHighlight] : [],
|
|
17
|
+
currentViewport: 'lg',
|
|
18
|
+
dimensions: [0, 0],
|
|
19
|
+
container: null,
|
|
20
|
+
coveLoadedEventRan: false,
|
|
21
|
+
isDraggingAnnotation: false,
|
|
22
|
+
imageId: `cove-${Math.random().toString(16).slice(-4)}`,
|
|
23
|
+
brushConfig: {
|
|
24
|
+
data: [],
|
|
25
|
+
isActive: false,
|
|
26
|
+
isBrushing: false
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
type State = {
|
|
32
|
+
isLoading: boolean
|
|
33
|
+
config: ChartConfig
|
|
34
|
+
stateData: object[]
|
|
35
|
+
colorScale: Function
|
|
36
|
+
excludedData: object[]
|
|
37
|
+
filteredData: object[]
|
|
38
|
+
seriesHighlight: string[]
|
|
39
|
+
currentViewport: ViewportSize
|
|
40
|
+
dimensions: DimensionsType
|
|
41
|
+
container: HTMLElement | null
|
|
42
|
+
coveLoadedEventRan: boolean
|
|
43
|
+
isDraggingAnnotation: boolean
|
|
44
|
+
imageId: string
|
|
45
|
+
brushConfig: {
|
|
46
|
+
data: object[]
|
|
47
|
+
isActive: boolean
|
|
48
|
+
isBrushing: boolean
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const reducer = (state: State, action: ChartActions) => {
|
|
53
|
+
switch (action.type) {
|
|
54
|
+
case 'SET_LOADING':
|
|
55
|
+
return { ...state, isLoading: action.payload }
|
|
56
|
+
case 'SET_CONFIG':
|
|
57
|
+
return { ...state, config: action.payload }
|
|
58
|
+
case 'UPDATE_CONFIG':
|
|
59
|
+
return { ...state, config: action.payload }
|
|
60
|
+
case 'SET_COLOR_SCALE':
|
|
61
|
+
return { ...state, colorScale: action.payload }
|
|
62
|
+
case 'SET_STATE_DATA':
|
|
63
|
+
return { ...state, stateData: action.payload }
|
|
64
|
+
case 'SET_EXCLUDED_DATA':
|
|
65
|
+
return { ...state, excludedData: action.payload }
|
|
66
|
+
case 'SET_FILTERED_DATA':
|
|
67
|
+
return { ...state, filteredData: action.payload }
|
|
68
|
+
case 'SET_SERIES_HIGHLIGHT':
|
|
69
|
+
return { ...state, seriesHighlight: action.payload }
|
|
70
|
+
case 'SET_VIEWPORT':
|
|
71
|
+
return { ...state, currentViewport: action.payload }
|
|
72
|
+
case 'SET_DIMENSIONS':
|
|
73
|
+
return { ...state, dimensions: action.payload }
|
|
74
|
+
case 'SET_CONTAINER':
|
|
75
|
+
return { ...state, container: action.payload }
|
|
76
|
+
case 'SET_LOADED_EVENT':
|
|
77
|
+
return { ...state, coveLoadedEventRan: action.payload }
|
|
78
|
+
case 'SET_DRAG_ANNOTATIONS':
|
|
79
|
+
return { ...state, isDraggingAnnotation: action.payload }
|
|
80
|
+
case 'SET_BRUSH_CONFIG':
|
|
81
|
+
return { ...state, brushConfig: action.payload }
|
|
82
|
+
}
|
|
83
|
+
}
|
package/src/types/ChartConfig.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { ConfidenceInterval } from '@cdc/core/types/ConfidenceInterval'
|
|
|
14
14
|
import { Region } from '@cdc/core/types/Region'
|
|
15
15
|
import { VizFilter } from '@cdc/core/types/VizFilter'
|
|
16
16
|
import { type Annotation } from '@cdc/core/types/Annotation'
|
|
17
|
+
import { Version } from '@cdc/core/types/Version'
|
|
17
18
|
|
|
18
19
|
export type ViewportSize = 'xxs' | 'xs' | 'sm' | 'md' | 'lg'
|
|
19
20
|
export type ChartColumns = Record<string, Column>
|
|
@@ -79,10 +80,11 @@ type Exclusions = {
|
|
|
79
80
|
|
|
80
81
|
export type Legend = CoreLegend & {
|
|
81
82
|
seriesHighlight: string[]
|
|
83
|
+
|
|
82
84
|
hideSuppressionLink: boolean
|
|
83
85
|
style: 'circles' | 'boxes' | 'gradient' | 'lines'
|
|
84
86
|
subStyle: 'linear blocks' | 'smooth'
|
|
85
|
-
|
|
87
|
+
hasShape: boolean
|
|
86
88
|
tickRotation: string
|
|
87
89
|
hideBorder: {
|
|
88
90
|
side: boolean
|
|
@@ -98,6 +100,8 @@ type Visual = {
|
|
|
98
100
|
hideBackgroundColor?: boolean
|
|
99
101
|
verticalHoverLine?: boolean
|
|
100
102
|
horizontalHoverLine?: boolean
|
|
103
|
+
lineDatapointSymbol: 'none' | 'standard'
|
|
104
|
+
maximumShapeAmount: 7
|
|
101
105
|
}
|
|
102
106
|
|
|
103
107
|
export type AllChartsConfig = {
|
|
@@ -131,7 +135,6 @@ export type AllChartsConfig = {
|
|
|
131
135
|
exclusions: Exclusions
|
|
132
136
|
filters: VizFilter[]
|
|
133
137
|
filterBehavior: FilterBehavior
|
|
134
|
-
fontSize: 'small' | 'medium' | 'large'
|
|
135
138
|
footnotes: string
|
|
136
139
|
forestPlot: ForestPlotConfigSettings
|
|
137
140
|
formattedData: Object[] & { urlFiltered: boolean }
|
|
@@ -184,7 +187,7 @@ export type AllChartsConfig = {
|
|
|
184
187
|
twoColor: { palette: string }
|
|
185
188
|
type: 'chart' | 'dashboard'
|
|
186
189
|
uid: string | number
|
|
187
|
-
version:
|
|
190
|
+
version: Version
|
|
188
191
|
visual: Visual
|
|
189
192
|
visualizationType: VisualizationType
|
|
190
193
|
visualizationSubType: string
|
|
@@ -23,9 +23,7 @@ type SharedChartContext = {
|
|
|
23
23
|
handleChartAriaLabels: (config: any) => string
|
|
24
24
|
handleDragStateChange: (isDragging: any) => void
|
|
25
25
|
highlight?: Function
|
|
26
|
-
|
|
27
|
-
// whether or not the legend is appearing below the chart
|
|
28
|
-
isLegendBottom?: boolean
|
|
26
|
+
handleShowAll?: Function
|
|
29
27
|
// whether or not the chart is viewed within the editor screen
|
|
30
28
|
isEditor?: boolean
|
|
31
29
|
// whether or not the user is dragging an annotation
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Calculates the first quartile (q1) and third quartile (q3) from an array of integers or decimals.
|
|
3
|
-
*
|
|
4
|
-
* @param {Array} arr - The array of integers or decimals.
|
|
5
|
-
* @returns {Object} An object containing the q1 and q3 values.
|
|
6
|
-
*/
|
|
7
|
-
import _ from 'lodash'
|
|
8
|
-
|
|
9
|
-
export const getQuartiles = (values: number[]): { q1: number; q3: number } => {
|
|
10
|
-
const sortedData: number[] = _.sortBy(values)
|
|
11
|
-
|
|
12
|
-
const quantile = (sortedData: number[], q: number): number => {
|
|
13
|
-
const position: number = (sortedData.length - 1) * q
|
|
14
|
-
const base: number = Math.floor(position)
|
|
15
|
-
const rest: number = position - base
|
|
16
|
-
if (sortedData[base + 1] !== undefined) {
|
|
17
|
-
return sortedData[base] + rest * (sortedData[base + 1] - sortedData[base])
|
|
18
|
-
} else {
|
|
19
|
-
return sortedData[base]
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
const q1: number = quantile(sortedData, 0.25)
|
|
24
|
-
const q3: number = quantile(sortedData, 0.75)
|
|
25
|
-
|
|
26
|
-
return { q1, q3 }
|
|
27
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { colorPalettesChart as colorPalettes, twoColorPalette } from '@cdc/core/data/colorPalettes'
|
|
2
|
-
import { scaleOrdinal } from '@visx/scale'
|
|
3
|
-
import { useContext } from 'react'
|
|
4
|
-
import ConfigContext from '../ConfigContext'
|
|
5
|
-
|
|
6
|
-
const useColorScale = () => {
|
|
7
|
-
const { config, data } = useContext(ConfigContext)
|
|
8
|
-
const { visualizationSubType, visualizationType, series, legend } = config
|
|
9
|
-
|
|
10
|
-
const generatePalette = colorsCount => {
|
|
11
|
-
if (!series?.length) return []
|
|
12
|
-
const isSpecialType = ['Paired Bar', 'Deviation Bar'].includes(visualizationType)
|
|
13
|
-
const chosenPalette = isSpecialType ? config.twoColor.palette : config.palette
|
|
14
|
-
const allPalettes = { ...colorPalettes, ...twoColorPalette }
|
|
15
|
-
let palette = config.customColors || allPalettes[chosenPalette]
|
|
16
|
-
while (colorsCount > palette.length) palette = palette.concat(palette)
|
|
17
|
-
return palette.slice(0, colorsCount)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
let colorScale = scaleOrdinal({
|
|
21
|
-
domain: config?.runtime?.seriesLabelsAll,
|
|
22
|
-
range: generatePalette(series.length)
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
if (visualizationType === 'Deviation Bar') {
|
|
26
|
-
const { targetLabel } = config.xAxis
|
|
27
|
-
colorScale = scaleOrdinal({
|
|
28
|
-
domain: [`Below ${targetLabel}`, `Above ${targetLabel}`],
|
|
29
|
-
range: generatePalette(2)
|
|
30
|
-
})
|
|
31
|
-
}
|
|
32
|
-
if (visualizationType === 'Bar' && visualizationSubType === 'regular' && series?.length === 1 && legend?.colorCode) {
|
|
33
|
-
const set = new Set(data?.map(d => d[legend.colorCode]))
|
|
34
|
-
colorScale = scaleOrdinal({
|
|
35
|
-
domain: [...set],
|
|
36
|
-
range: generatePalette([...set].length)
|
|
37
|
-
})
|
|
38
|
-
}
|
|
39
|
-
if (config.series.some(s => s.name)) {
|
|
40
|
-
const set = new Set(series.map(d => d.name || d.dataKey))
|
|
41
|
-
colorScale = colorScale = scaleOrdinal({
|
|
42
|
-
domain: [...set],
|
|
43
|
-
range: generatePalette(series.length)
|
|
44
|
-
})
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
return { colorScale }
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
export default useColorScale
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState } from 'react'
|
|
2
|
-
|
|
3
|
-
export default function useIntersectionObserver(elementRef, { threshold = 0, root = null, rootMargin = '0%', freezeOnceVisible = false }) {
|
|
4
|
-
const [entry, setEntry] = useState()
|
|
5
|
-
|
|
6
|
-
const frozen = entry?.isIntersecting && freezeOnceVisible
|
|
7
|
-
|
|
8
|
-
const updateEntry = ([entry]) => {
|
|
9
|
-
setEntry(entry)
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
useEffect(() => {
|
|
13
|
-
setTimeout(() => {
|
|
14
|
-
const node = elementRef?.current
|
|
15
|
-
const hasIOSupport = !!window.IntersectionObserver
|
|
16
|
-
|
|
17
|
-
if (!hasIOSupport || frozen || !node) return
|
|
18
|
-
|
|
19
|
-
const observerParams = { threshold, root, rootMargin }
|
|
20
|
-
const observer = new IntersectionObserver(updateEntry, observerParams)
|
|
21
|
-
|
|
22
|
-
observer.observe(node)
|
|
23
|
-
|
|
24
|
-
return () => observer.disconnect()
|
|
25
|
-
}, 500)
|
|
26
|
-
}, [elementRef, threshold, root, rootMargin, frozen])
|
|
27
|
-
|
|
28
|
-
return entry
|
|
29
|
-
}
|
package/src/hooks/useTopAxis.js
DELETED