@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
|
@@ -11,10 +11,11 @@ import { Line } from '@visx/shape'
|
|
|
11
11
|
import { Label } from '../../types/Label'
|
|
12
12
|
import { ChartConfig } from '../../types/ChartConfig'
|
|
13
13
|
import { ColorScale } from '../../types/ChartContext'
|
|
14
|
-
import { forwardRef } from 'react'
|
|
14
|
+
import { forwardRef, useState } from 'react'
|
|
15
15
|
import LegendSuppression from './Legend.Suppression'
|
|
16
16
|
import LegendGradient from '@cdc/core/components/Legend/Legend.Gradient'
|
|
17
17
|
import { DimensionsType } from '@cdc/core/types/Dimensions'
|
|
18
|
+
import { isLegendWrapViewport } from '@cdc/core/helpers/viewports'
|
|
18
19
|
|
|
19
20
|
export interface LegendProps {
|
|
20
21
|
colorScale: ColorScale
|
|
@@ -27,7 +28,6 @@ export interface LegendProps {
|
|
|
27
28
|
seriesHighlight: string[]
|
|
28
29
|
skipId: string
|
|
29
30
|
dimensions: DimensionsType // for responsive width legend
|
|
30
|
-
getTextWidth: (text: string, font: string) => string
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
/* eslint-disable jsx-a11y/no-noninteractive-tabindex, jsx-a11y/no-static-element-interactions */
|
|
@@ -42,24 +42,21 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
42
42
|
currentViewport,
|
|
43
43
|
formatLabels,
|
|
44
44
|
skipId = 'legend',
|
|
45
|
-
dimensions
|
|
46
|
-
getTextWidth
|
|
45
|
+
dimensions
|
|
47
46
|
},
|
|
48
47
|
ref
|
|
49
48
|
) => {
|
|
50
49
|
const { innerClasses, containerClasses } = useLegendClasses(config)
|
|
51
50
|
const { runtime, legend } = config
|
|
52
51
|
|
|
52
|
+
const [hasSuppression, setHasSuppression] = useState(false)
|
|
53
|
+
|
|
53
54
|
const isBottomOrSmallViewport =
|
|
54
|
-
legend?.position === 'bottom' || (
|
|
55
|
+
legend?.position === 'bottom' || (isLegendWrapViewport(currentViewport) && !legend.hide)
|
|
55
56
|
|
|
56
57
|
const legendClasses = {
|
|
57
|
-
marginBottom: getMarginBottom(
|
|
58
|
-
|
|
59
|
-
marginTop:
|
|
60
|
-
isBottomOrSmallViewport && config.orientation === 'horizontal'
|
|
61
|
-
? `${config.yAxis.label && config.isResponsiveTicks ? config.dynamicMarginTop : config.runtime.xAxis.size}px`
|
|
62
|
-
: getMarginTop(isBottomOrSmallViewport, config.brush.active, legend)
|
|
58
|
+
marginBottom: getMarginBottom(config, hasSuppression),
|
|
59
|
+
marginTop: getMarginTop(isBottomOrSmallViewport, config)
|
|
63
60
|
}
|
|
64
61
|
|
|
65
62
|
const { HighLightedBarUtils } = useHighlightedBars(config)
|
|
@@ -78,7 +75,6 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
78
75
|
{legend.label && <h3>{parse(legend.label)}</h3>}
|
|
79
76
|
{legend.description && <p>{parse(legend.description)}</p>}
|
|
80
77
|
<LegendGradient
|
|
81
|
-
getTextWidth={getTextWidth}
|
|
82
78
|
config={config}
|
|
83
79
|
{...getGradientConfig(config, formatLabels, colorScale)}
|
|
84
80
|
dimensions={dimensions}
|
|
@@ -133,9 +129,9 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
133
129
|
}}
|
|
134
130
|
role='button'
|
|
135
131
|
>
|
|
136
|
-
<div>
|
|
132
|
+
<div className='d-flex justify-content-center align-items-center'>
|
|
137
133
|
{config.visualizationType === 'Line' && config.legend.style === 'lines' ? (
|
|
138
|
-
<svg width={40} height={
|
|
134
|
+
<svg width={40} height={25}>
|
|
139
135
|
<Line
|
|
140
136
|
from={{ x: 10, y: 10 }}
|
|
141
137
|
to={{ x: 40, y: 10 }}
|
|
@@ -145,7 +141,7 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
145
141
|
/>
|
|
146
142
|
</svg>
|
|
147
143
|
) : (
|
|
148
|
-
<div
|
|
144
|
+
<div className='d-flex flex-column mt-1'>
|
|
149
145
|
<LegendShape
|
|
150
146
|
shape={config.legend.style === 'boxes' ? 'square' : 'circle'}
|
|
151
147
|
viewport={currentViewport}
|
|
@@ -204,7 +200,11 @@ const Legend: React.FC<LegendProps> = forwardRef(
|
|
|
204
200
|
})}
|
|
205
201
|
</div>
|
|
206
202
|
|
|
207
|
-
<LegendSuppression
|
|
203
|
+
<LegendSuppression
|
|
204
|
+
config={config}
|
|
205
|
+
isBottomOrSmallViewport={isBottomOrSmallViewport}
|
|
206
|
+
setHasSuppression={setHasSuppression}
|
|
207
|
+
/>
|
|
208
208
|
</>
|
|
209
209
|
)
|
|
210
210
|
}}
|
|
@@ -7,11 +7,11 @@ interface LegendProps {
|
|
|
7
7
|
isBottomOrSmallViewport: boolean
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
-
const LegendSuppression: React.FC<LegendProps> = ({ config, isBottomOrSmallViewport }) => {
|
|
10
|
+
const LegendSuppression: React.FC<LegendProps> = ({ config, isBottomOrSmallViewport, setHasSuppression }) => {
|
|
11
11
|
const { preliminaryData, visualizationType, visualizationSubType, legend } = config
|
|
12
12
|
|
|
13
13
|
const hasOpenCircleEffects = () =>
|
|
14
|
-
preliminaryData?.some(pd => pd.label && pd.type === 'effect' && pd.style
|
|
14
|
+
preliminaryData?.some(pd => pd.label && pd.type === 'effect' && pd.style !== 'Filled Circles') &&
|
|
15
15
|
['Line', 'Combo'].includes(visualizationType)
|
|
16
16
|
|
|
17
17
|
const shouldShowSuppressedLabels = () =>
|
|
@@ -100,6 +100,13 @@ const LegendSuppression: React.FC<LegendProps> = ({ config, isBottomOrSmallViewp
|
|
|
100
100
|
const getLegendContainerClass = () =>
|
|
101
101
|
legend.singleRow && isBottomOrSmallViewport ? 'legend-container__inner bottom single-row' : ''
|
|
102
102
|
|
|
103
|
+
const shouldShowSuppressedInfo = () =>
|
|
104
|
+
!config.legend.hideSuppressionLink &&
|
|
105
|
+
config.visualizationSubType !== 'stacked' &&
|
|
106
|
+
preliminaryData?.some(pd => pd.label && pd.type === 'suppression' && pd.value && (pd?.style || pd.symbol))
|
|
107
|
+
|
|
108
|
+
setHasSuppression(shouldShowSuppressedInfo())
|
|
109
|
+
|
|
103
110
|
return (
|
|
104
111
|
<React.Fragment>
|
|
105
112
|
{hasOpenCircleEffects() && (
|
|
@@ -115,24 +122,22 @@ const LegendSuppression: React.FC<LegendProps> = ({ config, isBottomOrSmallViewp
|
|
|
115
122
|
<div className={getLegendContainerClass()}>{renderSuppressedItems()}</div>
|
|
116
123
|
</React.Fragment>
|
|
117
124
|
)}
|
|
118
|
-
{
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
<
|
|
122
|
-
|
|
123
|
-
<
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
</div>
|
|
135
|
-
)}
|
|
125
|
+
{shouldShowSuppressedInfo() && (
|
|
126
|
+
<div className='legend-container__outer definition-link'>
|
|
127
|
+
<Icon alt='info-icon' display='info' />
|
|
128
|
+
<p>
|
|
129
|
+
This chart contains
|
|
130
|
+
<a // prettier-ignore
|
|
131
|
+
onClick={handleLinkClick}
|
|
132
|
+
data-tooltip-content='Data is suppressed to maintain statistical reliability. This occurs when the number of respondents or reported values does not meet the minimum reporting threshold.'
|
|
133
|
+
data-tooltip-id='my-tooltip'
|
|
134
|
+
href='no-router-link'
|
|
135
|
+
>
|
|
136
|
+
suppressed data
|
|
137
|
+
</a>
|
|
138
|
+
</p>
|
|
139
|
+
</div>
|
|
140
|
+
)}
|
|
136
141
|
|
|
137
142
|
<ReactTooltip // prettier-ignore
|
|
138
143
|
id='my-tooltip'
|
|
@@ -17,7 +17,6 @@ const Legend = forwardRef((props, ref) => {
|
|
|
17
17
|
transformedData: data,
|
|
18
18
|
currentViewport,
|
|
19
19
|
dimensions,
|
|
20
|
-
getTextWidth,
|
|
21
20
|
} = useContext(ConfigContext)
|
|
22
21
|
if (!config.legend) return null
|
|
23
22
|
// create fn to reverse labels while legend is Bottom. Legend-right , legend-left works by default.
|
|
@@ -28,7 +27,6 @@ const Legend = forwardRef((props, ref) => {
|
|
|
28
27
|
!['Box Plot'].includes(config.visualizationType) && (
|
|
29
28
|
<Fragment>
|
|
30
29
|
<LegendComponent
|
|
31
|
-
getTextWidth={getTextWidth}
|
|
32
30
|
dimensions={dimensions}
|
|
33
31
|
ref={ref}
|
|
34
32
|
skipId={props.skipId || 'legend'}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
export const getMarginTop = (isBottomOrSmallViewport, isBrushActive, legend) => {
|
|
2
|
-
if (!isBottomOrSmallViewport) return '0px'
|
|
3
|
-
if (isBrushActive && legend.position === 'bottom') return '35px'
|
|
4
|
-
}
|
|
5
|
-
|
|
6
1
|
export const getGradientConfig = (config, formatLabels, colorScale) => {
|
|
7
2
|
const defaultValue = [{ datum: '', index: 0, text: '', value: '' }]
|
|
8
3
|
|
|
@@ -15,21 +10,23 @@ export const getGradientConfig = (config, formatLabels, colorScale) => {
|
|
|
15
10
|
return { colors, labels }
|
|
16
11
|
}
|
|
17
12
|
|
|
18
|
-
export const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
const isLegendTop = config.legend?.position === 'top' && !config.legend.hide
|
|
22
|
-
|
|
23
|
-
let marginBottom = '0px'
|
|
24
|
-
if (isLegendTop && !isSuppressedActive) {
|
|
25
|
-
marginBottom = config.legend.hideBorder.topBottom ? '15px' : '25px'
|
|
26
|
-
}
|
|
27
|
-
if (isLegendTop && isSuppressedActive) {
|
|
28
|
-
marginBottom = '75px'
|
|
13
|
+
export const getMarginTop = (isBottomOrSmallViewport, config) => {
|
|
14
|
+
if (!isBottomOrSmallViewport) {
|
|
15
|
+
return '0px'
|
|
29
16
|
}
|
|
30
|
-
if (isBottomOrSmallViewport &&
|
|
31
|
-
|
|
17
|
+
if (isBottomOrSmallViewport && config.brush?.active) {
|
|
18
|
+
return '35px'
|
|
32
19
|
}
|
|
20
|
+
return '20px'
|
|
21
|
+
}
|
|
22
|
+
export const getMarginBottom = (config, hasSuppression) => {
|
|
23
|
+
const isLegendTop = config.legend?.position === 'top' && !config.legend.hide
|
|
24
|
+
|
|
25
|
+
let marginBottom = 0
|
|
26
|
+
|
|
27
|
+
if (isLegendTop) marginBottom = config.legend.hideBorder.topBottom ? 15 : 25
|
|
28
|
+
|
|
29
|
+
if (hasSuppression) marginBottom += 40
|
|
33
30
|
|
|
34
|
-
return marginBottom
|
|
31
|
+
return `${marginBottom}px`
|
|
35
32
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import React, { useContext } from 'react'
|
|
2
2
|
import ConfigContext from '../ConfigContext'
|
|
3
3
|
|
|
4
|
+
import { isLegendWrapViewport } from '@cdc/core/helpers/viewports'
|
|
5
|
+
|
|
4
6
|
type LegendWrapperProps = {
|
|
5
7
|
children: React.ReactNode
|
|
6
8
|
}
|
|
@@ -13,7 +15,7 @@ const LegendWrapper: React.FC<LegendWrapperProps> = props => {
|
|
|
13
15
|
const getLegendWrappingClasses = () => {
|
|
14
16
|
let classes = ['legend-wrapper', 'd-flex', 'flex-nowrap', 'w-100']
|
|
15
17
|
const { legend } = config
|
|
16
|
-
if (legend.position === 'bottom' || legend.position === 'top' ||
|
|
18
|
+
if (legend.position === 'bottom' || legend.position === 'top' || isLegendWrapViewport(currentViewport)) {
|
|
17
19
|
classes = classes.filter(item => item !== 'flex-nowrap')
|
|
18
20
|
classes.push('flex-wrap')
|
|
19
21
|
}
|