@cdc/chart 4.24.4 → 4.24.5
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 +32130 -31726
- package/index.html +7 -7
- package/package.json +2 -2
- package/src/CdcChart.tsx +17 -13
- package/src/_stories/Chart.stories.tsx +8 -0
- package/src/_stories/_mock/bar-chart-suppressed.json +474 -0
- package/src/components/AreaChart/components/AreaChart.jsx +2 -2
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +52 -47
- package/src/components/BarChart/components/BarChart.Vertical.tsx +77 -92
- package/src/components/DeviationBar.jsx +4 -2
- package/src/components/EditorPanel/EditorPanel.tsx +289 -601
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +19 -2
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +4 -5
- package/src/components/EditorPanel/useEditorPermissions.js +4 -1
- package/src/components/Legend/Legend.Component.tsx +62 -10
- package/src/components/LineChart/LineChartProps.ts +13 -6
- package/src/components/LineChart/components/LineChart.Circle.tsx +22 -11
- package/src/components/LineChart/helpers.ts +134 -10
- package/src/components/LineChart/index.tsx +69 -42
- package/src/components/LinearChart.jsx +155 -139
- package/src/components/ZoomBrush.tsx +40 -21
- package/src/data/initial-state.js +4 -4
- package/src/hooks/useBarChart.js +47 -22
- package/src/hooks/useMinMax.ts +21 -2
- package/src/hooks/useScales.ts +23 -23
- package/src/hooks/useTooltip.tsx +11 -11
- package/src/scss/main.scss +56 -6
- package/src/types/ChartConfig.ts +3 -13
- package/src/types/ChartContext.ts +4 -0
- package/src/_stories/ChartLine.preliminary.tsx +0 -19
- package/src/_stories/ChartSuppress.stories.tsx +0 -19
- package/src/_stories/_mock/suppress_mock.json +0 -911
- package/src/helpers/computeMarginBottom.ts +0 -56
|
@@ -14,10 +14,9 @@ interface Props {
|
|
|
14
14
|
yMax: number
|
|
15
15
|
}
|
|
16
16
|
const ZoomBrush: FC<Props> = props => {
|
|
17
|
-
const {
|
|
17
|
+
const { tableData, config, parseDate, formatDate, setBrushConfig } = useContext(ConfigContext)
|
|
18
18
|
const { fontSize } = useBarChart()
|
|
19
|
-
|
|
20
|
-
const [filteredData, setFilteredData] = useState([...data])
|
|
19
|
+
const [brushKey, setBrushKey] = useState(0)
|
|
21
20
|
const brushRef = useRef(null)
|
|
22
21
|
const radius = 15
|
|
23
22
|
|
|
@@ -34,7 +33,7 @@ const ZoomBrush: FC<Props> = props => {
|
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
const style = {
|
|
37
|
-
fill: '#
|
|
36
|
+
fill: '#AFA6A5 ',
|
|
38
37
|
stroke: 'blue',
|
|
39
38
|
fillOpacity: 0.8,
|
|
40
39
|
strokeOpacity: 0,
|
|
@@ -42,13 +41,12 @@ const ZoomBrush: FC<Props> = props => {
|
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
const onBrushChange = event => {
|
|
45
|
-
if (!event) return
|
|
46
|
-
|
|
44
|
+
if (!event || !event.xValues) return
|
|
47
45
|
const { xValues } = event
|
|
48
46
|
|
|
49
47
|
const dataKey = config.xAxis?.dataKey
|
|
50
48
|
|
|
51
|
-
const
|
|
49
|
+
const brushedData = tableData.filter(item => xValues.includes(item[dataKey]))
|
|
52
50
|
|
|
53
51
|
const endValue = xValues
|
|
54
52
|
.slice()
|
|
@@ -66,26 +64,45 @@ const ZoomBrush: FC<Props> = props => {
|
|
|
66
64
|
startValue: formatIfDate(startValue)
|
|
67
65
|
}))
|
|
68
66
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
...config,
|
|
75
|
-
brush: {
|
|
76
|
-
...config.brush,
|
|
77
|
-
data: filteredData
|
|
67
|
+
setBrushConfig(prev => {
|
|
68
|
+
return {
|
|
69
|
+
...prev,
|
|
70
|
+
isBrushing: brushRef.current?.state.isBrushing,
|
|
71
|
+
data: brushedData
|
|
78
72
|
}
|
|
79
73
|
})
|
|
80
|
-
}
|
|
74
|
+
}
|
|
81
75
|
|
|
82
|
-
//reset filters if brush is off
|
|
83
76
|
useEffect(() => {
|
|
84
77
|
if (!config.brush.active) {
|
|
85
|
-
|
|
78
|
+
setBrushKey(prevKey => prevKey + 1)
|
|
79
|
+
setBrushConfig({
|
|
80
|
+
data: [],
|
|
81
|
+
isActive: false,
|
|
82
|
+
isBrushing: false
|
|
83
|
+
})
|
|
86
84
|
}
|
|
87
85
|
}, [config.brush.active])
|
|
88
86
|
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (config.filters?.some(filter => filter.active)) {
|
|
89
|
+
setBrushKey(prevKey => prevKey + 1)
|
|
90
|
+
setBrushConfig(prev => {
|
|
91
|
+
return {
|
|
92
|
+
...prev,
|
|
93
|
+
data: tableData
|
|
94
|
+
}
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
return () =>
|
|
98
|
+
setBrushConfig(prev => {
|
|
99
|
+
return {
|
|
100
|
+
...prev,
|
|
101
|
+
data: []
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
}, [config.filters])
|
|
105
|
+
|
|
89
106
|
const calculateTop = (): number => {
|
|
90
107
|
const tickRotation = Number(config.xAxis.tickRotation) > 0 ? Number(config.xAxis.tickRotation) : 0
|
|
91
108
|
let top = 0
|
|
@@ -123,10 +140,12 @@ const ZoomBrush: FC<Props> = props => {
|
|
|
123
140
|
if (!['Line', 'Bar', 'Area Chart', 'Combo'].includes(config.visualizationType)) {
|
|
124
141
|
return
|
|
125
142
|
}
|
|
143
|
+
|
|
126
144
|
return (
|
|
127
145
|
<Group display={config.brush.active ? 'block' : 'none'} top={Number(props.yMax) + calculateTop()} left={Number(config.runtime.yAxis.size)} pointerEvents='fill'>
|
|
128
|
-
<rect fill='#
|
|
146
|
+
<rect fill='#F7F7F7 ' width={props.xMax} height={config.brush.height} rx={radius} />
|
|
129
147
|
<Brush
|
|
148
|
+
key={brushKey}
|
|
130
149
|
renderBrushHandle={props => <BrushHandle textProps={textProps} fontSize={fontSize[config.fontSize]} {...props} isBrushing={brushRef.current?.state.isBrushing} />}
|
|
131
150
|
innerRef={brushRef}
|
|
132
151
|
useWindowMoveEvents={true}
|
|
@@ -161,7 +180,7 @@ const BrushHandle = props => {
|
|
|
161
180
|
<Text pointerEvents='visiblePainted' dominantBaseline='hanging' x={0} verticalAnchor='start' textAnchor={textAnchor} fontSize={props.fontSize / 1.4} dy={10} y={15}>
|
|
162
181
|
{isLeft ? textProps.startValue : textProps.endValue}
|
|
163
182
|
</Text>
|
|
164
|
-
<path cursor='ew-resize' d='M0.5,10A6,6 0 0 1 6.5,16V14A6,6 0 0 1 0.5,20ZM2.5,18V12M4.5,18V12' fill={!isBrushing ? '#
|
|
183
|
+
<path cursor='ew-resize' d='M0.5,10A6,6 0 0 1 6.5,16V14A6,6 0 0 1 0.5,20ZM2.5,18V12M4.5,18V12' fill={!isBrushing ? '#000' : '#297EF1'} strokeWidth='1' transform={transform}></path>
|
|
165
184
|
</Group>
|
|
166
185
|
)
|
|
167
186
|
}
|
|
@@ -28,9 +28,7 @@ export default {
|
|
|
28
28
|
left: 5,
|
|
29
29
|
right: 5
|
|
30
30
|
},
|
|
31
|
-
suppressedData: [],
|
|
32
31
|
preliminaryData: [],
|
|
33
|
-
|
|
34
32
|
yAxis: {
|
|
35
33
|
hideAxis: false,
|
|
36
34
|
displayNumbersOnBar: false,
|
|
@@ -118,7 +116,9 @@ export default {
|
|
|
118
116
|
labelOffset: 65,
|
|
119
117
|
axisPadding: 200,
|
|
120
118
|
target: 0,
|
|
121
|
-
maxTickRotation: 0
|
|
119
|
+
maxTickRotation: 0,
|
|
120
|
+
showSuppressedSymbol: true,
|
|
121
|
+
showSuppressedLine: true
|
|
122
122
|
},
|
|
123
123
|
table: {
|
|
124
124
|
label: 'Data Table',
|
|
@@ -154,11 +154,11 @@ export default {
|
|
|
154
154
|
lineMode: false,
|
|
155
155
|
verticalSorted: false,
|
|
156
156
|
highlightOnHover: false,
|
|
157
|
+
hideSuppressedLabels: false,
|
|
157
158
|
seriesHighlight: []
|
|
158
159
|
},
|
|
159
160
|
brush: {
|
|
160
161
|
height: 25,
|
|
161
|
-
data: [],
|
|
162
162
|
active: false
|
|
163
163
|
},
|
|
164
164
|
exclusions: {
|
package/src/hooks/useBarChart.js
CHANGED
|
@@ -164,26 +164,13 @@ export const useBarChart = () => {
|
|
|
164
164
|
if (!match?.color) return false
|
|
165
165
|
return match
|
|
166
166
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
return
|
|
173
|
-
}
|
|
174
|
-
if (barWidth < 10) {
|
|
175
|
-
return 6
|
|
176
|
-
}
|
|
177
|
-
if (barWidth < 15) {
|
|
178
|
-
return 7
|
|
179
|
-
}
|
|
180
|
-
if (barWidth < 20) {
|
|
181
|
-
return 8
|
|
182
|
-
}
|
|
183
|
-
if (barWidth < 90) {
|
|
184
|
-
return 8
|
|
185
|
-
}
|
|
186
|
-
return 0
|
|
167
|
+
|
|
168
|
+
const shouldSuppress = bar => {
|
|
169
|
+
return config.preliminaryData?.some(pd => {
|
|
170
|
+
const matchesColumn = pd.column ? pd.column === bar.key : true
|
|
171
|
+
const matchesValue = String(bar.value) === String(pd.value) && pd.value !== ''
|
|
172
|
+
return matchesColumn && matchesValue && pd.symbol && pd.type === 'suppression'
|
|
173
|
+
})
|
|
187
174
|
}
|
|
188
175
|
|
|
189
176
|
const getAdditionalColumn = (series, xAxisDataValue) => {
|
|
@@ -223,14 +210,51 @@ export const useBarChart = () => {
|
|
|
223
210
|
if (config.legend.highlightOnHover && config.legend.behavior === 'highlight') setSeriesHighlight([])
|
|
224
211
|
}
|
|
225
212
|
|
|
213
|
+
const composeSuppressionBars = ({ bar }) => {
|
|
214
|
+
const suppresedBarHeight = config.xAxis.showSuppressedLine ? 3 : 0
|
|
215
|
+
const ASTERISK = 'Asterisk'
|
|
216
|
+
const getIconPadding = symbol => (String(symbol).includes(ASTERISK) ? -5 : -suppresedBarHeight * 3)
|
|
217
|
+
const getVerticalAnchor = symbol => {
|
|
218
|
+
return String(symbol).includes(ASTERISK) ? 'middle' : 'end'
|
|
219
|
+
}
|
|
220
|
+
const getIconSize = (symbol, barWidth) => {
|
|
221
|
+
switch (symbol) {
|
|
222
|
+
case ASTERISK:
|
|
223
|
+
return barWidth * 1.2
|
|
224
|
+
case 'Double ' + ASTERISK:
|
|
225
|
+
return barWidth
|
|
226
|
+
default:
|
|
227
|
+
return barWidth / 1.5
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function shouldSuppressBar() {
|
|
232
|
+
const isSuppressed = config.preliminaryData.some(pd => {
|
|
233
|
+
const selectedSuppressionColumn = !pd.column || pd.column === bar.key
|
|
234
|
+
const isValueMatch = String(pd.value) === String(bar.value) && pd.value !== '' && pd.type === 'suppression'
|
|
235
|
+
|
|
236
|
+
return isValueMatch && selectedSuppressionColumn
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
return isSuppressed && config.xAxis.showSuppressedSymbol
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
return {
|
|
243
|
+
suppresedBarHeight,
|
|
244
|
+
getIconSize,
|
|
245
|
+
getIconPadding,
|
|
246
|
+
getVerticalAnchor,
|
|
247
|
+
isSuppressed: shouldSuppressBar()
|
|
248
|
+
}
|
|
249
|
+
}
|
|
226
250
|
return {
|
|
227
|
-
generateIconSize,
|
|
228
251
|
isHorizontal,
|
|
229
252
|
barBorderWidth,
|
|
230
253
|
lollipopBarWidth,
|
|
231
254
|
lollipopShapeSize,
|
|
232
255
|
isLabelBelowBar,
|
|
233
256
|
displayNumbersOnBar,
|
|
257
|
+
shouldSuppress,
|
|
234
258
|
section,
|
|
235
259
|
isRounded,
|
|
236
260
|
isStacked,
|
|
@@ -249,6 +273,7 @@ export const useBarChart = () => {
|
|
|
249
273
|
hoveredBar,
|
|
250
274
|
setHoveredBar,
|
|
251
275
|
onMouseOverBar,
|
|
252
|
-
onMouseLeaveBar
|
|
276
|
+
onMouseLeaveBar,
|
|
277
|
+
composeSuppressionBars
|
|
253
278
|
}
|
|
254
279
|
}
|
package/src/hooks/useMinMax.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ChartConfig } from '../types/ChartConfig'
|
|
2
|
+
import _ from 'lodash'
|
|
2
3
|
|
|
3
4
|
type UseMinMaxProps = {
|
|
4
5
|
/** config - standard chart config */
|
|
@@ -11,11 +12,13 @@ type UseMinMaxProps = {
|
|
|
11
12
|
existPositiveValue: boolean
|
|
12
13
|
/** data - standard data array */
|
|
13
14
|
data: Object[]
|
|
15
|
+
/** Table data -data array Filtered & Excluded */
|
|
16
|
+
tableData: Object[]
|
|
14
17
|
/** isAllLine: if all series are line type including dashed lines */
|
|
15
18
|
isAllLine: boolean
|
|
16
19
|
}
|
|
17
20
|
|
|
18
|
-
const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAllLine }: UseMinMaxProps) => {
|
|
21
|
+
const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAllLine, tableData }: UseMinMaxProps) => {
|
|
19
22
|
let min = 0
|
|
20
23
|
let max = 0
|
|
21
24
|
|
|
@@ -147,7 +150,23 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
|
|
|
147
150
|
|
|
148
151
|
if (config.visualizationType === 'Line') {
|
|
149
152
|
const isMinValid = config.useLogScale ? enteredMinValue >= 0 && enteredMinValue < minValue : enteredMinValue < minValue
|
|
150
|
-
|
|
153
|
+
// update minValue for (0) Suppression points
|
|
154
|
+
const suppressedMinValue = tableData?.some((dataItem, index) => {
|
|
155
|
+
return config.preliminaryData?.some(pd => {
|
|
156
|
+
if (pd.type !== 'suppression' || !pd.style) return false
|
|
157
|
+
|
|
158
|
+
// Filter data item based on current series keys and check if pd.value is present
|
|
159
|
+
const relevantData = _.pick(dataItem, config.runtime?.seriesKeys)
|
|
160
|
+
const isValuePresent = _.values(relevantData).includes(pd.value)
|
|
161
|
+
|
|
162
|
+
// Check for value match condition
|
|
163
|
+
const valueMatch = pd.column ? dataItem[pd.column] === pd.value : isValuePresent
|
|
164
|
+
|
|
165
|
+
// Return true if the value matches and it's either the first or the last item
|
|
166
|
+
return valueMatch && (index === 0 || index === tableData.length - 1)
|
|
167
|
+
})
|
|
168
|
+
})
|
|
169
|
+
min = enteredMinValue && isMinValid ? enteredMinValue : suppressedMinValue ? 0 : minValue
|
|
151
170
|
}
|
|
152
171
|
//If data value max wasn't provided, calculate it
|
|
153
172
|
if (max === Number.MIN_VALUE) {
|
package/src/hooks/useScales.ts
CHANGED
|
@@ -72,7 +72,7 @@ const useScales = (properties: useScaleProps) => {
|
|
|
72
72
|
domain: [xAxisMin, xAxisMax],
|
|
73
73
|
range: [0, xMax]
|
|
74
74
|
})
|
|
75
|
-
|
|
75
|
+
|
|
76
76
|
xScale.type = scaleTypes.TIME
|
|
77
77
|
seriesScale = composeScaleBand(seriesDomain, [0, config.barThickness * xMax], 0)
|
|
78
78
|
}
|
|
@@ -239,34 +239,34 @@ const useScales = (properties: useScaleProps) => {
|
|
|
239
239
|
export default useScales
|
|
240
240
|
|
|
241
241
|
export const getTickValues = (xAxisDataMapped, xScale, num) => {
|
|
242
|
-
const xDomain = xScale.domain()
|
|
243
|
-
|
|
244
|
-
if(xScale.type === 'time'){
|
|
245
|
-
const xDomainMax = xAxisDataMapped[xAxisDataMapped.length - 1]
|
|
246
|
-
const xDomainMin = xAxisDataMapped[0]
|
|
247
|
-
const step = (xDomainMax - xDomainMin) / (num - 1)
|
|
248
|
-
const tickValues = []
|
|
249
|
-
for(let i = xDomainMax; i >= xDomainMin; i -= step){
|
|
250
|
-
tickValues.push(i)
|
|
242
|
+
const xDomain = xScale.domain()
|
|
243
|
+
|
|
244
|
+
if (xScale.type === 'time') {
|
|
245
|
+
const xDomainMax = xAxisDataMapped[xAxisDataMapped.length - 1]
|
|
246
|
+
const xDomainMin = xAxisDataMapped[0]
|
|
247
|
+
const step = (xDomainMax - xDomainMin) / (num - 1)
|
|
248
|
+
const tickValues = []
|
|
249
|
+
for (let i = xDomainMax; i >= xDomainMin; i -= step) {
|
|
250
|
+
tickValues.push(i)
|
|
251
251
|
}
|
|
252
|
-
if(tickValues[tickValues.length - 1] !== xDomainMin){
|
|
253
|
-
tickValues.push(xDomainMin)
|
|
252
|
+
if (tickValues[tickValues.length - 1] !== xDomainMin) {
|
|
253
|
+
tickValues.push(xDomainMin)
|
|
254
254
|
}
|
|
255
|
-
tickValues.reverse()
|
|
256
|
-
|
|
257
|
-
return tickValues
|
|
255
|
+
tickValues.reverse()
|
|
256
|
+
|
|
257
|
+
return tickValues
|
|
258
258
|
}
|
|
259
259
|
|
|
260
|
-
if(xDomain.length > 2){
|
|
261
|
-
const step = num || 1
|
|
262
|
-
const tickValues = []
|
|
263
|
-
for(let i = xDomain.length; i > 0; i -= step){
|
|
264
|
-
const adjustedIndex = Math.max(Math.round(i) - 1, 0)
|
|
265
|
-
tickValues.push(xDomain[adjustedIndex])
|
|
260
|
+
if (xDomain.length > 2) {
|
|
261
|
+
const step = num || 1
|
|
262
|
+
const tickValues = []
|
|
263
|
+
for (let i = xDomain.length; i > 0; i -= step) {
|
|
264
|
+
const adjustedIndex = Math.max(Math.round(i) - 1, 0)
|
|
265
|
+
tickValues.push(xDomain[adjustedIndex])
|
|
266
266
|
}
|
|
267
|
-
tickValues.reverse()
|
|
267
|
+
tickValues.reverse()
|
|
268
268
|
|
|
269
|
-
return tickValues
|
|
269
|
+
return tickValues
|
|
270
270
|
}
|
|
271
271
|
}
|
|
272
272
|
|
package/src/hooks/useTooltip.tsx
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
1
1
|
import { useContext } from 'react'
|
|
2
|
+
// Local imports
|
|
2
3
|
import ConfigContext from '../ConfigContext'
|
|
3
4
|
import { type ChartContext } from '../types/ChartContext'
|
|
4
|
-
|
|
5
|
-
// third party
|
|
6
|
-
import { localPoint } from '@visx/event'
|
|
7
|
-
import { bisector } from 'd3-array'
|
|
8
|
-
import { DataTransform } from '@cdc/core/helpers/DataTransform'
|
|
9
|
-
const transform = new DataTransform()
|
|
10
|
-
|
|
11
5
|
import { formatNumber as formatColNumber } from '@cdc/core/helpers/cove/number'
|
|
12
6
|
import { isDateScale } from '@cdc/core/helpers/cove/date'
|
|
7
|
+
// Third-party library imports
|
|
8
|
+
import { localPoint } from '@visx/event'
|
|
9
|
+
import { bisector } from 'd3-array'
|
|
13
10
|
|
|
14
11
|
export const useTooltip = props => {
|
|
15
|
-
const { tableData, config, formatNumber, capitalize, formatDate, formatTooltipsDate, parseDate, setSharedFilter } = useContext<ChartContext>(ConfigContext)
|
|
12
|
+
const { tableData: data, config, formatNumber, capitalize, formatDate, formatTooltipsDate, parseDate, setSharedFilter } = useContext<ChartContext>(ConfigContext)
|
|
16
13
|
const { xScale, yScale, showTooltip, hideTooltip } = props
|
|
17
14
|
const { xAxis, visualizationType, orientation, yAxis, runtime } = config
|
|
18
|
-
const data = transform.applySuppression(tableData, config.suppressedData)
|
|
19
15
|
/**
|
|
20
16
|
* Provides the tooltip information based on the tooltip data array and svg cursor coordinates
|
|
21
17
|
* @function getTooltipInformation
|
|
@@ -141,9 +137,13 @@ export const useTooltip = props => {
|
|
|
141
137
|
if (visualizationType !== 'Pie' && visualizationType !== 'Forest Plot') {
|
|
142
138
|
tooltipItems.push(
|
|
143
139
|
...getIncludedTooltipSeries()
|
|
144
|
-
?.filter(
|
|
140
|
+
?.filter(seriesKey => config.series?.find(item => item.dataKey === seriesKey && item?.tooltip) || config.xAxis?.dataKey == seriesKey)
|
|
145
141
|
?.flatMap(seriesKey => {
|
|
146
|
-
|
|
142
|
+
let formattedValue = seriesKey === config.xAxis.dataKey ? resolvedScaleValues[0]?.[seriesKey] : formatNumber(resolvedScaleValues[0]?.[seriesKey], getAxisPosition(seriesKey))
|
|
143
|
+
const suppressed = config.preliminaryData?.find(pd => pd.label && pd.type === 'suppression' && pd.displayTooltip && resolvedScaleValues[0]?.[seriesKey] === pd.value && (!pd.column || seriesKey === pd.column))
|
|
144
|
+
if (suppressed) {
|
|
145
|
+
formattedValue = suppressed.label
|
|
146
|
+
}
|
|
147
147
|
return resolvedScaleValues?.[0]?.[seriesKey] ? [[seriesKey, formattedValue, getAxisPosition(seriesKey)]] : []
|
|
148
148
|
})
|
|
149
149
|
)
|
package/src/scss/main.scss
CHANGED
|
@@ -13,9 +13,21 @@
|
|
|
13
13
|
flex-direction: column-reverse;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
+
.cdc-open-viz-module.type-dashboard {
|
|
17
|
+
.cdc-open-viz-module.type-chart.isEditor {
|
|
18
|
+
.cdc-chart-inner-container {
|
|
19
|
+
background: white;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
16
24
|
.cdc-open-viz-module.type-chart {
|
|
17
25
|
@import 'DataTable';
|
|
18
26
|
|
|
27
|
+
&.isEditor .cdc-chart-inner-container {
|
|
28
|
+
background: white;
|
|
29
|
+
}
|
|
30
|
+
|
|
19
31
|
border-radius: 3px;
|
|
20
32
|
|
|
21
33
|
.checkbox-group {
|
|
@@ -75,11 +87,10 @@
|
|
|
75
87
|
margin-bottom: 20px;
|
|
76
88
|
}
|
|
77
89
|
|
|
90
|
+
.subtext,
|
|
91
|
+
.subtext--responsive-ticks,
|
|
78
92
|
.section-subtext {
|
|
79
|
-
padding:
|
|
80
|
-
}
|
|
81
|
-
.subtext--responsive-ticks {
|
|
82
|
-
margin-top: 3em;
|
|
93
|
+
padding: 0 1rem;
|
|
83
94
|
}
|
|
84
95
|
|
|
85
96
|
.legend-container {
|
|
@@ -148,13 +159,18 @@
|
|
|
148
159
|
|
|
149
160
|
h3 {
|
|
150
161
|
font-size: 1.3rem;
|
|
162
|
+
@include breakpoint(xs) {
|
|
163
|
+
font-size: $font-small + 0.4em;
|
|
164
|
+
}
|
|
151
165
|
}
|
|
152
166
|
|
|
153
167
|
h3,
|
|
154
168
|
p {
|
|
155
169
|
margin-bottom: 0.8em;
|
|
170
|
+
}
|
|
171
|
+
p {
|
|
156
172
|
@include breakpoint(xs) {
|
|
157
|
-
font-size: $font-small
|
|
173
|
+
font-size: $font-small;
|
|
158
174
|
}
|
|
159
175
|
}
|
|
160
176
|
& div.legend-item {
|
|
@@ -198,18 +214,50 @@
|
|
|
198
214
|
}
|
|
199
215
|
}
|
|
200
216
|
|
|
217
|
+
.div[class*='Asterisk'] {
|
|
218
|
+
transform: 0;
|
|
219
|
+
}
|
|
220
|
+
|
|
201
221
|
.legend-preliminary {
|
|
202
222
|
display: flex;
|
|
203
223
|
flex-direction: row;
|
|
204
224
|
align-items: center;
|
|
225
|
+
font-size: 1em;
|
|
226
|
+
vertical-align: middle;
|
|
227
|
+
margin-bottom: 0.5em;
|
|
228
|
+
|
|
205
229
|
@include breakpoint(xs) {
|
|
206
230
|
font-size: $font-small;
|
|
207
231
|
}
|
|
232
|
+
& > span {
|
|
233
|
+
display: flex;
|
|
234
|
+
justify-items: center;
|
|
235
|
+
align-items: center;
|
|
236
|
+
white-space: nowrap;
|
|
237
|
+
font-size: 1em;
|
|
238
|
+
margin-right: 8px;
|
|
239
|
+
max-height: 1px;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
& > span[class*='Asterisk'] {
|
|
243
|
+
transform: scale(1.8);
|
|
244
|
+
margin-top: 15px;
|
|
245
|
+
}
|
|
246
|
+
& > span[class*='Dagger'] {
|
|
247
|
+
margin-top: 2px;
|
|
248
|
+
}
|
|
249
|
+
& > span[class*='Sign'] {
|
|
250
|
+
margin-top: 1px;
|
|
251
|
+
}
|
|
208
252
|
|
|
209
253
|
& > svg {
|
|
210
254
|
width: 50px;
|
|
211
255
|
height: 23px;
|
|
212
256
|
}
|
|
257
|
+
|
|
258
|
+
& > p {
|
|
259
|
+
margin: 0;
|
|
260
|
+
}
|
|
213
261
|
}
|
|
214
262
|
|
|
215
263
|
.visx-tooltip {
|
|
@@ -651,8 +699,10 @@
|
|
|
651
699
|
padding: 1em;
|
|
652
700
|
}
|
|
653
701
|
|
|
654
|
-
.subtext
|
|
702
|
+
.subtext,
|
|
703
|
+
.subtext--responsive-ticks {
|
|
655
704
|
margin-top: 0px;
|
|
705
|
+
padding: 0 1rem;
|
|
656
706
|
}
|
|
657
707
|
|
|
658
708
|
.isEditor {
|
package/src/types/ChartConfig.ts
CHANGED
|
@@ -12,6 +12,7 @@ import { Legend } from '@cdc/core/types/Legend'
|
|
|
12
12
|
import { ConfidenceInterval } from '@cdc/core/types/ConfidenceInterval'
|
|
13
13
|
import { Region } from '@cdc/core/types/Region'
|
|
14
14
|
import { type PreliminaryDataItem } from '../components/LineChart/LineChartProps'
|
|
15
|
+
import { VizFilter } from '@cdc/core/types/VizFilter'
|
|
15
16
|
|
|
16
17
|
export type ChartColumns = Record<string, Column>
|
|
17
18
|
|
|
@@ -39,18 +40,6 @@ type Exclusions = {
|
|
|
39
40
|
dateEnd: string
|
|
40
41
|
}
|
|
41
42
|
|
|
42
|
-
type Filter = {
|
|
43
|
-
active: string
|
|
44
|
-
type: 'url'
|
|
45
|
-
columnName: string
|
|
46
|
-
showDropdown: boolean
|
|
47
|
-
filterStyle: string
|
|
48
|
-
label: string
|
|
49
|
-
order: 'asc' | 'desc' | 'cust'
|
|
50
|
-
values: string[]
|
|
51
|
-
queryParameter: string
|
|
52
|
-
}
|
|
53
|
-
|
|
54
43
|
export type Legend = {
|
|
55
44
|
seriesHighlight: string[]
|
|
56
45
|
additionalCategories: string[]
|
|
@@ -109,7 +98,7 @@ type AllChartsConfig = {
|
|
|
109
98
|
description: string
|
|
110
99
|
dynamicMarginTop: number
|
|
111
100
|
exclusions: Exclusions
|
|
112
|
-
filters:
|
|
101
|
+
filters: VizFilter[]
|
|
113
102
|
filterBehavior: FilterBehavior
|
|
114
103
|
fontSize: 'small' | 'medium' | 'large'
|
|
115
104
|
footnotes: string
|
|
@@ -161,6 +150,7 @@ type AllChartsConfig = {
|
|
|
161
150
|
twoColor: { palette: string }
|
|
162
151
|
type: 'chart' | 'dashboard'
|
|
163
152
|
useLogScale: boolean
|
|
153
|
+
uid: string | number
|
|
164
154
|
visual: Visual
|
|
165
155
|
visualizationType: 'Area Chart' | 'Bar' | 'Box Plot' | 'Deviation Bar' | 'Forest Plot' | 'Line' | 'Paired Bar' | 'Pie' | 'Scatter Plot' | 'Spark Line' | 'Combo' | 'Forecasting' | 'Sankey'
|
|
166
156
|
visualizationSubType: string
|
|
@@ -21,6 +21,10 @@ type SharedChartContext = {
|
|
|
21
21
|
legendIsolateValues?: string[]
|
|
22
22
|
setLegendIsolateValues?: Function
|
|
23
23
|
getTextWidth?: () => string | number
|
|
24
|
+
brushConfig: { data: []; isBrushing: boolean; isActive: boolean }
|
|
25
|
+
setBrushConfig: Function
|
|
26
|
+
clean: Function
|
|
27
|
+
capitalize: (value: string) => string
|
|
24
28
|
}
|
|
25
29
|
|
|
26
30
|
// Line Chart Specific Context
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
-
import chartLinepreliminary from './_mock/preliminary_mock.json'
|
|
3
|
-
|
|
4
|
-
import Chart from '../CdcChart'
|
|
5
|
-
|
|
6
|
-
const meta: Meta<typeof Chart> = {
|
|
7
|
-
title: 'Components/Templates/Chart/Line/Preliminary',
|
|
8
|
-
component: Chart
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
type Story = StoryObj<typeof Chart>
|
|
12
|
-
|
|
13
|
-
export const Line_Chart: Story = {
|
|
14
|
-
args: {
|
|
15
|
-
config: chartLinepreliminary
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export default meta
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
-
import suppressMock from './_mock/suppress_mock.json'
|
|
3
|
-
|
|
4
|
-
import Chart from '../CdcChart'
|
|
5
|
-
|
|
6
|
-
const meta: Meta<typeof Chart> = {
|
|
7
|
-
title: 'Components/Templates/Chart/Suppress',
|
|
8
|
-
component: Chart
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
type Story = StoryObj<typeof Chart>
|
|
12
|
-
|
|
13
|
-
export const Horizontal_Chart: Story = {
|
|
14
|
-
args: {
|
|
15
|
-
config: suppressMock
|
|
16
|
-
}
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export default meta
|