@cdc/chart 4.25.6 → 4.25.8
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 +53500 -32825
- package/package.json +3 -2
- package/src/CdcChart.tsx +9 -2
- package/src/CdcChartComponent.tsx +30 -12
- package/src/_stories/Chart.BoxPlot.stories.tsx +35 -0
- package/src/_stories/Chart.stories.tsx +0 -7
- package/src/_stories/Chart.tooltip.stories.tsx +35 -275
- package/src/_stories/_mock/bar-chart-suppressed.json +2 -80
- package/src/_stories/_mock/boxplot_multiseries.json +252 -166
- package/src/components/AreaChart/components/AreaChart.Stacked.jsx +1 -1
- package/src/components/AreaChart/components/AreaChart.jsx +4 -8
- package/src/components/BarChart/components/BarChart.Horizontal.tsx +45 -7
- package/src/components/BarChart/components/BarChart.StackedHorizontal.tsx +1 -1
- package/src/components/BarChart/components/BarChart.Vertical.tsx +36 -4
- package/src/components/BoxPlot/BoxPlot.Horizontal.tsx +131 -0
- package/src/components/BoxPlot/{BoxPlot.tsx → BoxPlot.Vertical.tsx} +4 -4
- package/src/components/BoxPlot/helpers/index.ts +32 -12
- package/src/components/Brush/BrushChart.tsx +65 -10
- package/src/components/Brush/BrushController.tsx +71 -0
- package/src/components/Brush/types.tsx +8 -0
- package/src/components/BrushChart.tsx +1 -1
- package/src/components/EditorPanel/EditorPanel.tsx +19 -14
- package/src/components/EditorPanel/components/Panels/Panel.Annotate.tsx +2 -2
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +2 -2
- package/src/components/EditorPanel/components/Panels/Panel.Series.tsx +2 -34
- package/src/components/Forecasting/{Forecasting.jsx → Forecasting.tsx} +32 -12
- package/src/components/Legend/Legend.Component.tsx +16 -1
- package/src/components/Legend/Legend.tsx +3 -1
- package/src/components/Legend/LegendGroup/LegendGroup.tsx +1 -0
- package/src/components/Legend/helpers/index.ts +2 -2
- package/src/components/LineChart/components/LineChart.BumpCircle.tsx +27 -26
- package/src/components/LineChart/helpers.ts +7 -7
- package/src/components/LinearChart.tsx +130 -75
- package/src/data/initial-state.js +12 -15
- package/src/helpers/countNumOfTicks.ts +4 -19
- package/src/helpers/filterAndShiftLinearDateTicks.ts +58 -0
- package/src/helpers/getBridgedData.ts +13 -0
- package/src/helpers/tests/getBridgedData.test.ts +64 -0
- package/src/hooks/useScales.ts +42 -42
- package/src/hooks/useTooltip.tsx +3 -2
- package/src/index.jsx +6 -1
- package/src/scss/main.scss +2 -4
- package/src/store/chart.actions.ts +2 -2
- package/src/store/chart.reducer.ts +4 -12
- package/src/types/ChartConfig.ts +1 -6
- package/src/components/BoxPlot/index.tsx +0 -3
- package/src/components/Brush/BrushController..tsx +0 -39
package/src/hooks/useScales.ts
CHANGED
|
@@ -44,7 +44,7 @@ const useScales = (properties: useScaleProps) => {
|
|
|
44
44
|
const xAxisType = config.runtime.xAxis.type
|
|
45
45
|
const isHorizontal = config.orientation === 'horizontal'
|
|
46
46
|
const { visualizationType, xAxis, forestPlot } = config
|
|
47
|
-
|
|
47
|
+
const paddingRange = ['Area Chart', 'Forecasting'].includes(config.visualizationType) ? 1 : 1 - config.barThickness
|
|
48
48
|
// define scales
|
|
49
49
|
let xScale = null
|
|
50
50
|
let yScale = null
|
|
@@ -68,22 +68,16 @@ const useScales = (properties: useScaleProps) => {
|
|
|
68
68
|
|
|
69
69
|
// handle Vertical bars
|
|
70
70
|
if (!isHorizontal) {
|
|
71
|
-
xScale = composeScaleBand(xAxisDataMapped, [0, xMax],
|
|
71
|
+
xScale = composeScaleBand(xAxisDataMapped, [0, xMax], paddingRange)
|
|
72
72
|
yScale = composeYScale(properties)
|
|
73
73
|
seriesScale = composeScaleBand(seriesDomain, [0, xScale.bandwidth()], 0)
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// handle Linear scaled viz
|
|
77
|
-
if (config.xAxis.type === 'date' && !isHorizontal) {
|
|
78
|
-
const xAxisDataMappedSorted = sortXAxisData(xAxisDataMapped, config.xAxis.sortByRecentDate)
|
|
79
|
-
xScale = composeScaleBand(xAxisDataMappedSorted, [0, xMax], 1 - config.barThickness)
|
|
80
|
-
}
|
|
81
|
-
|
|
82
76
|
// handle Linear scaled viz
|
|
83
77
|
if (config.xAxis.type === 'date' && !isHorizontal) {
|
|
84
78
|
const sorted = sortXAxisData(xAxisDataMapped, config.xAxis.sortByRecentDate)
|
|
85
79
|
|
|
86
|
-
xScale = composeScaleBand(sorted, [0, xMax],
|
|
80
|
+
xScale = composeScaleBand(sorted, [0, xMax], paddingRange)
|
|
87
81
|
xScale.type = scaleTypes.BAND
|
|
88
82
|
}
|
|
89
83
|
|
|
@@ -153,44 +147,50 @@ const useScales = (properties: useScaleProps) => {
|
|
|
153
147
|
|
|
154
148
|
// handle Box plot
|
|
155
149
|
if (visualizationType === 'Box Plot') {
|
|
156
|
-
const
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
150
|
+
const {
|
|
151
|
+
boxplot: { plots, hideOutliers },
|
|
152
|
+
xAxis: { dataKey },
|
|
153
|
+
orientation,
|
|
154
|
+
runtime: { seriesKeys },
|
|
155
|
+
series,
|
|
156
|
+
barThickness
|
|
157
|
+
} = config
|
|
158
|
+
|
|
159
|
+
// 1) merge outliers + fences
|
|
160
|
+
let lo = min,
|
|
161
|
+
hi = max
|
|
162
|
+
for (const { columnOutliers = [], columnLowerBounds: lb, columnUpperBounds: ub } of plots) {
|
|
163
|
+
if (!hideOutliers && columnOutliers.length) {
|
|
164
|
+
lo = Math.min(lo, ...columnOutliers)
|
|
165
|
+
hi = Math.max(hi, ...columnOutliers)
|
|
166
|
+
}
|
|
167
|
+
lo = Math.min(lo, lb)
|
|
168
|
+
hi = Math.max(hi, ub)
|
|
169
169
|
}
|
|
170
|
+
;[min, max] = [lo, hi]
|
|
170
171
|
|
|
171
|
-
//
|
|
172
|
-
|
|
173
|
-
let highestFence = Math.max(...config.boxplot.plots.map(item => item.columnUpperBounds))
|
|
172
|
+
// 2) unique categories
|
|
173
|
+
const cats = Array.from(new Set(data.map(d => d[dataKey])))
|
|
174
174
|
|
|
175
|
-
if (
|
|
176
|
-
|
|
175
|
+
if (orientation === 'horizontal') {
|
|
176
|
+
xScale = composeXScale({ min, max, xMax, config })
|
|
177
|
+
xScale.type = scaleTypes.LINEAR
|
|
177
178
|
|
|
178
|
-
|
|
179
|
+
yScale = composeScaleBand(cats, [0, yMax], 0.4)
|
|
180
|
+
seriesScale = composeScaleBand(seriesKeys, [0, yScale.bandwidth()], 0.3)
|
|
181
|
+
} else {
|
|
182
|
+
xScale = composeScaleBand(cats, [0, xMax], 1 - barThickness)
|
|
183
|
+
xScale.type = scaleTypes.BAND
|
|
179
184
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
range: [0, xMax],
|
|
190
|
-
domain: categories
|
|
191
|
-
})
|
|
192
|
-
xScale.type = scaleTypes.BAND
|
|
193
|
-
seriesScale = composeScaleBand(domain, range)
|
|
185
|
+
// numeric → Y
|
|
186
|
+
yScale = composeYScale({ min, max, yMax, config, leftMax: 0 })
|
|
187
|
+
|
|
188
|
+
seriesScale = composeScaleBand(
|
|
189
|
+
series.map(s => s.dataKey),
|
|
190
|
+
[0, xScale.bandwidth()],
|
|
191
|
+
0
|
|
192
|
+
)
|
|
193
|
+
}
|
|
194
194
|
}
|
|
195
195
|
|
|
196
196
|
// handle Paired bar
|
package/src/hooks/useTooltip.tsx
CHANGED
|
@@ -286,10 +286,11 @@ export const useTooltip = props => {
|
|
|
286
286
|
let minDistance = Number.MAX_VALUE
|
|
287
287
|
let offset = x
|
|
288
288
|
|
|
289
|
+
const barThicknessOffset = config.xAxis.type === 'date' ? xScale.bandwidth() / 2 : 0
|
|
289
290
|
data.forEach(d => {
|
|
290
291
|
const xPosition = isDateScale(xAxis) ? xScale(parseDate(d[xAxis.dataKey])) : xScale(d[xAxis.dataKey])
|
|
291
292
|
let bwOffset = config.barHeight
|
|
292
|
-
const distance = Math.abs(Number(xPosition - offset + (isClick ? bwOffset * 2 : 0)))
|
|
293
|
+
const distance = Math.abs(Number(xPosition + barThicknessOffset - offset + (isClick ? bwOffset * 2 : 0)))
|
|
293
294
|
|
|
294
295
|
if (distance <= minDistance) {
|
|
295
296
|
minDistance = distance
|
|
@@ -593,7 +594,7 @@ export const useTooltip = props => {
|
|
|
593
594
|
|
|
594
595
|
return (
|
|
595
596
|
<li style={style} className='tooltip-body mb-1'>
|
|
596
|
-
{displayText}
|
|
597
|
+
{displayText !== undefined ? parse(String(displayText)) : displayText}
|
|
597
598
|
</li>
|
|
598
599
|
)
|
|
599
600
|
}
|
package/src/index.jsx
CHANGED
|
@@ -14,6 +14,11 @@ let domContainer = document.getElementsByClassName('react-container')[0]
|
|
|
14
14
|
|
|
15
15
|
ReactDOM.createRoot(domContainer).render(
|
|
16
16
|
<React.StrictMode>
|
|
17
|
-
<CdcChart
|
|
17
|
+
<CdcChart
|
|
18
|
+
interactionLabel={domContainer.attributes['data-config']?.value}
|
|
19
|
+
configUrl={domContainer.attributes['data-config'].value}
|
|
20
|
+
isEditor={isEditor}
|
|
21
|
+
isDebug={isDebug}
|
|
22
|
+
/>
|
|
18
23
|
</React.StrictMode>
|
|
19
24
|
)
|
package/src/scss/main.scss
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
@import '@cdc/core/styles/accessibility';
|
|
2
|
+
|
|
1
3
|
@mixin breakpoint($class) {
|
|
2
4
|
@if $class == xs {
|
|
3
5
|
@media (max-width: 767px) {
|
|
@@ -513,10 +515,6 @@
|
|
|
513
515
|
}
|
|
514
516
|
}
|
|
515
517
|
|
|
516
|
-
[tabindex]:focus-visible {
|
|
517
|
-
outline: 2px solid rgb(0, 95, 204) !important;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
518
|
// ANIMATIONS
|
|
521
519
|
// Pie Chart Animations
|
|
522
520
|
.animated-pie {
|
|
@@ -16,7 +16,7 @@ type SET_DIMENSIONS = Action<'SET_DIMENSIONS', DimensionsType>
|
|
|
16
16
|
type SET_CONTAINER = Action<'SET_CONTAINER', object>
|
|
17
17
|
type SET_LOADED_EVENT = Action<'SET_LOADED_EVENT', boolean>
|
|
18
18
|
type SET_DRAG_ANNOTATIONS = Action<'SET_DRAG_ANNOTATIONS', boolean>
|
|
19
|
-
type
|
|
19
|
+
type SET_BRUSH_DATA = Action<'SET_BRUSH_DATA', object[]>
|
|
20
20
|
type ChartActions =
|
|
21
21
|
| SET_CONFIG
|
|
22
22
|
| UPDATE_CONFIG
|
|
@@ -31,6 +31,6 @@ type ChartActions =
|
|
|
31
31
|
| SET_LOADED_EVENT
|
|
32
32
|
| SET_DRAG_ANNOTATIONS
|
|
33
33
|
| SET_LOADING
|
|
34
|
-
|
|
|
34
|
+
| SET_BRUSH_DATA
|
|
35
35
|
|
|
36
36
|
export default ChartActions
|
|
@@ -18,11 +18,7 @@ type ChartState = {
|
|
|
18
18
|
coveLoadedEventRan: boolean
|
|
19
19
|
isDraggingAnnotation: boolean
|
|
20
20
|
imageId: string
|
|
21
|
-
|
|
22
|
-
data: object[]
|
|
23
|
-
isActive: boolean
|
|
24
|
-
isBrushing: boolean
|
|
25
|
-
}
|
|
21
|
+
brushData: object[] | []
|
|
26
22
|
}
|
|
27
23
|
|
|
28
24
|
export const getInitialState = (configObj: ChartConfig): ChartState => {
|
|
@@ -41,11 +37,7 @@ export const getInitialState = (configObj: ChartConfig): ChartState => {
|
|
|
41
37
|
coveLoadedEventRan: false,
|
|
42
38
|
isDraggingAnnotation: false,
|
|
43
39
|
imageId: `cove-${Math.random().toString(16).slice(-4)}`,
|
|
44
|
-
|
|
45
|
-
data: [],
|
|
46
|
-
isActive: false,
|
|
47
|
-
isBrushing: false
|
|
48
|
-
}
|
|
40
|
+
brushData: []
|
|
49
41
|
}
|
|
50
42
|
}
|
|
51
43
|
|
|
@@ -77,7 +69,7 @@ export const reducer = (state: ChartState, action: ChartActions): ChartState =>
|
|
|
77
69
|
return { ...state, coveLoadedEventRan: action.payload }
|
|
78
70
|
case 'SET_DRAG_ANNOTATIONS':
|
|
79
71
|
return { ...state, isDraggingAnnotation: action.payload }
|
|
80
|
-
case '
|
|
81
|
-
return { ...state,
|
|
72
|
+
case 'SET_BRUSH_DATA':
|
|
73
|
+
return { ...state, brushData: action.payload }
|
|
82
74
|
}
|
|
83
75
|
}
|
package/src/types/ChartConfig.ts
CHANGED
|
@@ -44,7 +44,7 @@ export interface PreliminaryDataItem {
|
|
|
44
44
|
iconCode: string
|
|
45
45
|
label: string
|
|
46
46
|
lineCode: string
|
|
47
|
-
|
|
47
|
+
seriesKeys: string[]
|
|
48
48
|
style: string
|
|
49
49
|
symbol: string
|
|
50
50
|
type: 'effect' | 'suppression'
|
|
@@ -120,11 +120,6 @@ export type AllChartsConfig = {
|
|
|
120
120
|
barStyle: 'lollipop' | 'rounded' | 'flat'
|
|
121
121
|
barThickness: number
|
|
122
122
|
boxplot: BoxPlot
|
|
123
|
-
brush: {
|
|
124
|
-
active: boolean
|
|
125
|
-
data: object[]
|
|
126
|
-
isBrushing: boolean
|
|
127
|
-
}
|
|
128
123
|
chartMessage: { noData?: string }
|
|
129
124
|
color: string
|
|
130
125
|
colorMatchLineSeriesLabels: boolean
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { useState, useEffect, useContext } from 'react'
|
|
2
|
-
import ConfigContext, { ChartDispatchContext } from '../../ConfigContext'
|
|
3
|
-
import ZoomBrush from './BrushChart'
|
|
4
|
-
const BrushController = ({ yMax, xMax }) => {
|
|
5
|
-
const { tableData, config, parseDate, dashboardConfig } = useContext(ConfigContext)
|
|
6
|
-
const dataKey = config.xAxis.dataKey
|
|
7
|
-
const [brushKey, setBrushKey] = useState(0)
|
|
8
|
-
const dispatch = useContext(ChartDispatchContext)
|
|
9
|
-
const sharedFilters = dashboardConfig?.dashboard?.sharedFilters ?? []
|
|
10
|
-
const isDashboardFilters = sharedFilters?.length > 0
|
|
11
|
-
const [brushPosition, setBrushPosition] = useState({
|
|
12
|
-
start: { x: 0 },
|
|
13
|
-
end: { x: xMax }
|
|
14
|
-
})
|
|
15
|
-
|
|
16
|
-
const handleBrushChange = (bounds: any) => {
|
|
17
|
-
const selected = bounds.xValues || []
|
|
18
|
-
const filteredData = tableData.filter(row => selected.includes(row[dataKey]))
|
|
19
|
-
dispatch({ type: 'SET_BRUSH_DATA', payload: filteredData })
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// whenever your other filters change:
|
|
23
|
-
useEffect(() => {
|
|
24
|
-
setBrushPosition({ start: { x: 0 }, end: { x: xMax } })
|
|
25
|
-
dispatch({ type: 'SET_BRUSH_DATA', payload: [] })
|
|
26
|
-
setBrushKey(k => k + 1)
|
|
27
|
-
}, [config.filters, config.exclusions, config.brush?.active, isDashboardFilters])
|
|
28
|
-
|
|
29
|
-
return (
|
|
30
|
-
<ZoomBrush
|
|
31
|
-
xMax={xMax}
|
|
32
|
-
yMax={yMax}
|
|
33
|
-
brushPosition={brushPosition}
|
|
34
|
-
onBrushChange={handleBrushChange}
|
|
35
|
-
brushKey={brushKey}
|
|
36
|
-
/>
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
export default BrushController
|