@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.
Files changed (84) hide show
  1. package/dist/cdcchart.js +79900 -78999
  2. package/examples/feature/boxplot/boxplot.json +2 -157
  3. package/examples/feature/boxplot/testing.csv +23 -38
  4. package/examples/feature/tests-non-numerics/example-combo-bar-nonnumeric.json +579 -49
  5. package/examples/private/ehdi.json +29939 -0
  6. package/examples/private/line-issue.json +497 -0
  7. package/examples/private/not-loading.json +360 -0
  8. package/index.html +11 -15
  9. package/package.json +2 -2
  10. package/src/CdcChart.tsx +92 -1512
  11. package/src/CdcChartComponent.tsx +1113 -0
  12. package/src/ConfigContext.tsx +6 -1
  13. package/src/_stories/Chart.Anchors.stories.tsx +1 -1
  14. package/src/_stories/Chart.CustomColors.stories.tsx +1 -1
  15. package/src/_stories/Chart.DynamicSeries.stories.tsx +17 -2
  16. package/src/_stories/Chart.Filters.stories.tsx +19 -0
  17. package/src/_stories/Chart.Legend.Gradient.stories.tsx +2 -2
  18. package/src/_stories/Chart.ScatterPlot.stories.tsx +19 -0
  19. package/src/_stories/Chart.tooltip.stories.tsx +1 -2
  20. package/src/_stories/ChartAnnotation.stories.tsx +1 -1
  21. package/src/_stories/ChartAxisLabels.stories.tsx +1 -1
  22. package/src/_stories/ChartAxisTitles.stories.tsx +1 -1
  23. package/src/_stories/ChartEditor.stories.tsx +1 -1
  24. package/src/_stories/ChartLine.Suppression.stories.tsx +1 -1
  25. package/src/_stories/ChartLine.Symbols.stories.tsx +18 -0
  26. package/src/_stories/ChartPrefixSuffix.stories.tsx +1 -1
  27. package/src/_stories/_mock/line_chart_symbols.json +437 -0
  28. package/src/_stories/_mock/scatterplot-image-download.json +1244 -0
  29. package/src/components/Annotations/components/AnnotationDraggable.tsx +3 -11
  30. package/src/components/Annotations/components/AnnotationDropdown.tsx +3 -3
  31. package/src/components/Axis/Categorical.Axis.tsx +3 -4
  32. package/src/components/BarChart/components/BarChart.Horizontal.tsx +14 -5
  33. package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +10 -4
  34. package/src/components/BarChart/components/BarChart.Vertical.tsx +5 -7
  35. package/src/components/BarChart/components/BarChart.jsx +24 -4
  36. package/src/components/BarChart/components/context.tsx +1 -0
  37. package/src/components/BoxPlot/BoxPlot.tsx +34 -32
  38. package/src/components/BoxPlot/helpers/index.ts +108 -18
  39. package/src/components/BrushChart.tsx +44 -24
  40. package/src/components/DeviationBar.jsx +2 -6
  41. package/src/components/EditorPanel/EditorPanel.tsx +64 -8
  42. package/src/components/EditorPanel/components/Panels/Panel.General.tsx +4 -0
  43. package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +3 -1
  44. package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +44 -7
  45. package/src/components/EditorPanel/helpers/updateFieldRankByValue.ts +6 -1
  46. package/src/components/ForestPlot/ForestPlot.tsx +176 -26
  47. package/src/components/Legend/Legend.Component.tsx +29 -38
  48. package/src/components/Legend/Legend.Suppression.tsx +3 -5
  49. package/src/components/Legend/Legend.tsx +2 -2
  50. package/src/components/Legend/LegendLine.Shape.tsx +51 -0
  51. package/src/components/Legend/helpers/createFormatLabels.tsx +29 -26
  52. package/src/components/Legend/helpers/getLegendClasses.ts +20 -38
  53. package/src/components/Legend/helpers/index.ts +22 -9
  54. package/src/components/Legend/tests/getLegendClasses.test.ts +3 -20
  55. package/src/components/LineChart/components/LineChart.Circle.tsx +104 -94
  56. package/src/components/LineChart/index.tsx +6 -2
  57. package/src/components/LinearChart.tsx +77 -43
  58. package/src/components/PairedBarChart.jsx +2 -9
  59. package/src/components/ZoomBrush.tsx +5 -7
  60. package/src/data/initial-state.js +6 -3
  61. package/src/helpers/getBoxPlotConfig.ts +68 -0
  62. package/src/helpers/getColorScale.ts +24 -0
  63. package/src/helpers/getComboChartConfig.ts +42 -0
  64. package/src/helpers/getExcludedData.ts +37 -0
  65. package/src/helpers/getTopAxis.ts +7 -0
  66. package/src/helpers/isConvertLineToBarGraph.ts +10 -3
  67. package/src/hooks/useBarChart.ts +40 -13
  68. package/src/hooks/{useHighlightedBars.js → useHighlightedBars.ts} +2 -1
  69. package/src/hooks/useIntersectionObserver.ts +37 -0
  70. package/src/hooks/useMinMax.ts +11 -8
  71. package/src/hooks/useReduceData.ts +1 -1
  72. package/src/hooks/useScales.ts +10 -0
  73. package/src/hooks/useTooltip.tsx +21 -2
  74. package/src/index.jsx +1 -0
  75. package/src/scss/DataTable.scss +0 -5
  76. package/src/scss/main.scss +31 -116
  77. package/src/store/chart.actions.ts +40 -0
  78. package/src/store/chart.reducer.ts +83 -0
  79. package/src/types/ChartConfig.ts +6 -3
  80. package/src/types/ChartContext.ts +1 -3
  81. package/src/helpers/getQuartiles.ts +0 -27
  82. package/src/hooks/useColorScale.ts +0 -50
  83. package/src/hooks/useIntersectionObserver.jsx +0 -29
  84. 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
+ }
@@ -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: string
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
- highlightReset?: Function
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
- }
@@ -1,6 +0,0 @@
1
- export default function useTopAxis(config) {
2
- // When to show top axis
3
- const hasTopAxis = config.visualizationType === 'Bar' || config.visualizationType === 'Combo' || config.visualizationType === 'Line'
4
-
5
- return { hasTopAxis }
6
- }