@cdc/chart 4.23.10 → 4.23.11
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 +30989 -29057
- package/examples/feature/bar/example-bar-chart.json +1 -46
- package/examples/feature/bar/lollipop.json +156 -0
- package/examples/feature/combo/planet-combo-example-config.json +99 -9
- package/examples/feature/dev-4261.json +399 -0
- package/examples/feature/forest-plot/{broken.json → linear.json} +55 -50
- package/examples/feature/forest-plot/logarithmic.json +306 -0
- package/examples/feature/line/line-points.json +340 -0
- package/examples/feature/regions/index.json +462 -0
- package/examples/gallery/bar-chart-vertical/combo-line-chart.json +181 -48
- package/examples/sparkline-multilple.json +846 -0
- package/index.html +10 -6
- package/package.json +3 -3
- package/src/CdcChart.tsx +75 -63
- package/src/_stories/Chart.stories.tsx +188 -0
- package/src/_stories/Chart.tooltip.stories.tsx +305 -0
- package/src/_stories/ChartBrush.stories.tsx +19 -0
- package/src/_stories/ChartSuppress.stories.tsx +19 -0
- package/src/_stories/_mock/brush_mock.json +393 -0
- package/src/_stories/_mock/suppress_mock.json +911 -0
- package/src/components/AreaChart.Stacked.jsx +4 -5
- package/src/components/AreaChart.jsx +6 -35
- package/src/components/{BarChart.Horizontal.jsx → BarChart.Horizontal.tsx} +106 -29
- package/src/components/{BarChart.StackedHorizontal.jsx → BarChart.StackedHorizontal.tsx} +22 -17
- package/src/components/{BarChart.StackedVertical.jsx → BarChart.StackedVertical.tsx} +22 -26
- package/src/components/{BarChart.Vertical.jsx → BarChart.Vertical.tsx} +175 -31
- package/src/components/BarChart.jsx +1 -1
- package/src/components/DeviationBar.jsx +4 -3
- package/src/components/EditorPanel.jsx +176 -50
- package/src/components/ForestPlot/ForestPlotProps.ts +11 -0
- package/src/components/ForestPlot/Readme.md +0 -0
- package/src/components/ForestPlot/index.scss +1 -0
- package/src/components/{ForestPlot.jsx → ForestPlot/index.tsx} +51 -31
- package/src/components/ForestPlotSettings.jsx +162 -113
- package/src/components/Legend.jsx +36 -3
- package/src/components/{LineChart.Circle.tsx → LineChart/LineChart.Circle.tsx} +26 -29
- package/src/components/LineChart/LineChartProps.ts +17 -0
- package/src/components/LineChart/index.scss +1 -0
- package/src/components/{LineChart.tsx → LineChart/index.tsx} +64 -35
- package/src/components/LinearChart.jsx +120 -60
- package/src/components/PairedBarChart.jsx +2 -2
- package/src/components/Series.jsx +22 -3
- package/src/components/ZoomBrush.tsx +168 -0
- package/src/data/initial-state.js +27 -12
- package/src/hooks/useBarChart.js +71 -7
- package/src/hooks/useColorScale.ts +50 -0
- package/src/hooks/useEditorPermissions.js +22 -4
- package/src/hooks/{useMinMax.js → useMinMax.ts} +75 -23
- package/src/hooks/{useRightAxis.js → useRightAxis.ts} +10 -2
- package/src/hooks/{useScales.js → useScales.ts} +64 -17
- package/src/hooks/useTooltip.jsx +68 -41
- package/src/scss/main.scss +3 -35
- package/src/types/ChartConfig.ts +43 -0
- package/src/types/ChartContext.ts +38 -0
- package/src/types/ChartProps.ts +7 -0
- package/src/types/ForestPlot.ts +60 -0
|
@@ -1,16 +1,30 @@
|
|
|
1
|
-
import { scaleBand, scaleLinear, scaleLog, scalePoint, scaleTime } from '@visx/scale'
|
|
1
|
+
import { LogScaleConfig, scaleBand, scaleLinear, scaleLog, scalePoint, scaleTime } from '@visx/scale'
|
|
2
2
|
import { useContext } from 'react'
|
|
3
3
|
import ConfigContext from '../ConfigContext'
|
|
4
|
-
|
|
4
|
+
import { ChartConfig } from '../types/ChartConfig'
|
|
5
|
+
import { ChartContext } from '../types/ChartContext'
|
|
6
|
+
|
|
7
|
+
type useScaleProps = {
|
|
8
|
+
config: ChartConfig // standard chart config
|
|
9
|
+
data: Object[] // standard data array
|
|
10
|
+
max: number // maximum value from useMinMax hook
|
|
11
|
+
min: number // minimum value from useMinMax hook
|
|
12
|
+
xAxisDataMapped: Object[] // array of x axis date/category items
|
|
13
|
+
xMax: number // chart svg width
|
|
14
|
+
yMax: number // chart svg height
|
|
15
|
+
}
|
|
5
16
|
|
|
6
|
-
const useScales = properties => {
|
|
17
|
+
const useScales = (properties: useScaleProps) => {
|
|
7
18
|
let { xAxisDataMapped, xMax, yMax, min, max, config, data } = properties
|
|
8
|
-
|
|
19
|
+
|
|
20
|
+
const { rawData, dimensions } = useContext<ChartContext>(ConfigContext)
|
|
9
21
|
|
|
10
22
|
const [screenWidth, screenHeight] = dimensions
|
|
11
23
|
const seriesDomain = config.runtime.barSeriesKeys || config.runtime.seriesKeys
|
|
12
24
|
const xAxisType = config.runtime.xAxis.type
|
|
13
25
|
const isHorizontal = config.orientation === 'horizontal'
|
|
26
|
+
const getXAxisDataKeys = d => d[config.runtime.originalXAxis.dataKey]
|
|
27
|
+
const xAxisDataKeysMapped = data.map(d => getXAxisDataKeys(d))
|
|
14
28
|
|
|
15
29
|
const { visualizationType } = config
|
|
16
30
|
|
|
@@ -21,6 +35,7 @@ const useScales = properties => {
|
|
|
21
35
|
let g1xScale = null
|
|
22
36
|
let seriesScale = null
|
|
23
37
|
let xScaleNoPadding = null
|
|
38
|
+
let xScaleBrush = null
|
|
24
39
|
|
|
25
40
|
const scaleTypes = {
|
|
26
41
|
TIME: 'time',
|
|
@@ -41,6 +56,7 @@ const useScales = properties => {
|
|
|
41
56
|
|
|
42
57
|
// handle Vertical bars
|
|
43
58
|
if (!isHorizontal) {
|
|
59
|
+
xScaleBrush = composeScalePoint(xAxisDataKeysMapped, [0, xMax], 0.5)
|
|
44
60
|
xScale = composeScalePoint(xAxisDataMapped, [0, xMax], 0.5)
|
|
45
61
|
xScale.type = scaleTypes.POINT
|
|
46
62
|
yScale = composeYScale(properties)
|
|
@@ -53,6 +69,7 @@ const useScales = properties => {
|
|
|
53
69
|
domain: [Math.min(...xAxisDataMapped), Math.max(...xAxisDataMapped)],
|
|
54
70
|
range: [0, xMax]
|
|
55
71
|
})
|
|
72
|
+
xScaleBrush = xScale
|
|
56
73
|
xScale.type = scaleTypes.LINEAR
|
|
57
74
|
}
|
|
58
75
|
|
|
@@ -170,21 +187,49 @@ const useScales = properties => {
|
|
|
170
187
|
const leftWidthOffsetMobile = (Number(config.forestPlot.leftWidthOffsetMobile) / 100) * xMax
|
|
171
188
|
|
|
172
189
|
if (screenWidth > 480) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
190
|
+
if (config.forestPlot.type === 'Linear') {
|
|
191
|
+
xScale = scaleLinear({
|
|
192
|
+
domain: [Math.min(...data.map(d => parseFloat(d[config.forestPlot.lower]))) - xAxisPadding, Math.max(...data.map(d => parseFloat(d[config.forestPlot.upper]))) + xAxisPadding],
|
|
193
|
+
range: [leftWidthOffset, xMax - rightWidthOffset]
|
|
194
|
+
})
|
|
195
|
+
xScale.type = scaleTypes.LINEAR
|
|
196
|
+
}
|
|
197
|
+
if (config.forestPlot.type === 'Logarithmic') {
|
|
198
|
+
let max = Math.max(...data.map(d => parseFloat(d[config.forestPlot.upper])))
|
|
199
|
+
let fp_min = Math.min(...data.map(d => parseFloat(d[config.forestPlot.lower])))
|
|
200
|
+
|
|
201
|
+
xScale = scaleLog<LogScaleConfig>({
|
|
202
|
+
domain: [fp_min, max],
|
|
203
|
+
range: [leftWidthOffset, xMax - rightWidthOffset],
|
|
204
|
+
nice: true
|
|
205
|
+
})
|
|
206
|
+
xScale.type = scaleTypes.LOG
|
|
207
|
+
}
|
|
178
208
|
} else {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
209
|
+
if (config.forestPlot.type === 'Linear') {
|
|
210
|
+
xScale = scaleLinear({
|
|
211
|
+
domain: [Math.min(...data.map(d => parseFloat(d[config.forestPlot.lower]))) - xAxisPadding, Math.max(...data.map(d => parseFloat(d[config.forestPlot.upper]))) + xAxisPadding],
|
|
212
|
+
range: [leftWidthOffsetMobile, xMax - rightWidthOffsetMobile],
|
|
213
|
+
type: scaleTypes.LINEAR
|
|
214
|
+
})
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (config.forestPlot.type === 'Logarithmic') {
|
|
218
|
+
let max = Math.max(...data.map(d => parseFloat(d[config.forestPlot.upper])))
|
|
219
|
+
let fp_min = Math.min(...data.map(d => parseFloat(d[config.forestPlot.lower])))
|
|
220
|
+
|
|
221
|
+
xScale = scaleLog<LogScaleConfig>({
|
|
222
|
+
domain: [fp_min, max],
|
|
223
|
+
range: [leftWidthOffset, xMax - rightWidthOffset],
|
|
224
|
+
nice: true,
|
|
225
|
+
base: max > 1 ? 10 : 2,
|
|
226
|
+
round: false,
|
|
227
|
+
type: scaleTypes.LOG
|
|
228
|
+
})
|
|
229
|
+
}
|
|
184
230
|
}
|
|
185
231
|
}
|
|
186
|
-
|
|
187
|
-
return { xScale, yScale, seriesScale, g1xScale, g2xScale, xScaleNoPadding }
|
|
232
|
+
return { xScale, yScale, seriesScale, g1xScale, g2xScale, xScaleNoPadding, xScaleBrush }
|
|
188
233
|
}
|
|
189
234
|
|
|
190
235
|
export default useScales
|
|
@@ -205,11 +250,13 @@ const composeXScale = ({ min, max, xMax, config }) => {
|
|
|
205
250
|
})
|
|
206
251
|
}
|
|
207
252
|
|
|
208
|
-
const composeYScale = ({ min, max, yMax, config }) => {
|
|
253
|
+
const composeYScale = ({ min, max, yMax, config, leftMax }) => {
|
|
209
254
|
// Adjust min value if using logarithmic scale
|
|
210
255
|
min = config.useLogScale && min >= 0 && min < 1 ? min + 0.1 : min
|
|
211
256
|
// Select the appropriate scale function
|
|
212
257
|
const scaleFunc = config.useLogScale ? scaleLog : scaleLinear
|
|
258
|
+
|
|
259
|
+
if (config.visualizationType === 'Combo') max = leftMax
|
|
213
260
|
// Return the configured scale function
|
|
214
261
|
return scaleFunc({
|
|
215
262
|
domain: [min, max],
|
package/src/hooks/useTooltip.jsx
CHANGED
|
@@ -5,14 +5,16 @@ import { defaultStyles } from '@visx/tooltip'
|
|
|
5
5
|
// third party
|
|
6
6
|
import { localPoint } from '@visx/event'
|
|
7
7
|
import { bisector } from 'd3-array'
|
|
8
|
+
import { DataTransform } from '@cdc/core/helpers/DataTransform'
|
|
9
|
+
const transform = new DataTransform()
|
|
8
10
|
|
|
9
11
|
import { formatNumber as formatColNumber } from '@cdc/core/helpers/cove/number'
|
|
10
12
|
|
|
11
13
|
export const useTooltip = props => {
|
|
12
|
-
const { tableData
|
|
14
|
+
const { tableData, config, formatNumber, capitalize, formatDate, parseDate, setSharedFilter } = useContext(ConfigContext)
|
|
13
15
|
const { xScale, yScale, showTooltip, hideTooltip } = props
|
|
14
16
|
const { xAxis, visualizationType, orientation, yAxis, runtime } = config
|
|
15
|
-
|
|
17
|
+
const data = transform.applySuppression(tableData, config.suppressedData)
|
|
16
18
|
/**
|
|
17
19
|
* Provides the tooltip information based on the tooltip data array and svg cursor coordinates
|
|
18
20
|
* @function getTooltipInformation
|
|
@@ -51,13 +53,12 @@ export const useTooltip = props => {
|
|
|
51
53
|
const { x, y } = eventSvgCoords
|
|
52
54
|
|
|
53
55
|
// Additional data for pie charts
|
|
54
|
-
const { data: pieChartData, arc } = additionalChartData
|
|
56
|
+
const { data: pieChartData, arc } = additionalChartData ?? {}
|
|
55
57
|
|
|
56
58
|
const closestXScaleValue = getXValueFromCoordinate(x - Number(config.yAxis.size || 0))
|
|
57
59
|
|
|
58
60
|
const includedSeries = visualizationType !== 'Pie' ? config.series.filter(series => series.tooltip === true).map(item => item.dataKey) : config.series.map(item => item.dataKey)
|
|
59
61
|
includedSeries.push(config.xAxis.dataKey)
|
|
60
|
-
|
|
61
62
|
if (config.visualizationType === 'Forecasting') {
|
|
62
63
|
config.series.map(s => {
|
|
63
64
|
s.confidenceIntervals.map(c => {
|
|
@@ -68,6 +69,17 @@ export const useTooltip = props => {
|
|
|
68
69
|
})
|
|
69
70
|
})
|
|
70
71
|
}
|
|
72
|
+
function getColumnNames(columns) {
|
|
73
|
+
let names = []
|
|
74
|
+
for (let key in columns) {
|
|
75
|
+
if (columns.hasOwnProperty(key)) {
|
|
76
|
+
names.push(columns[key].name)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return names
|
|
80
|
+
}
|
|
81
|
+
includedSeries.push(...getColumnNames(config.columns))
|
|
82
|
+
includedSeries.push(...getColumnNames(config.columns))
|
|
71
83
|
|
|
72
84
|
const yScaleValues = getYScaleValues(closestXScaleValue, includedSeries)
|
|
73
85
|
|
|
@@ -75,7 +87,7 @@ export const useTooltip = props => {
|
|
|
75
87
|
|
|
76
88
|
const resolvedScaleValues = orientation === 'vertical' ? yScaleValues : xScaleValues
|
|
77
89
|
|
|
78
|
-
const forestPlotXValue = visualizationType === 'Forest Plot' ? data?.filter(d => d[xAxis.dataKey] === getClosestYValue(y))[0][config.forestPlot.estimateField] : null
|
|
90
|
+
// const forestPlotXValue = visualizationType === 'Forest Plot' ? data?.filter(d => d[xAxis.dataKey] === getClosestYValue(y))?.[0]?.[config.forestPlot.estimateField] : null
|
|
79
91
|
|
|
80
92
|
const getAxisPosition = seriesKey => {
|
|
81
93
|
const seriesObj = config.series.filter(s => s.dataKey === seriesKey)[0]
|
|
@@ -84,49 +96,61 @@ export const useTooltip = props => {
|
|
|
84
96
|
}
|
|
85
97
|
|
|
86
98
|
const getTooltipDataArray = () => {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
let closestValue = getClosestYValue(y, colVals.name)
|
|
100
|
-
|
|
101
|
-
const formattedValue = formatColNumber(closestValue, 'left', true, config, formattingParams)
|
|
99
|
+
const columns = config.columns
|
|
100
|
+
const columnsWithTooltips = []
|
|
101
|
+
const tooltipItems = []
|
|
102
|
+
|
|
103
|
+
for (const [colKeys, colVals] of Object.entries(columns)) {
|
|
104
|
+
const formattingParams = {
|
|
105
|
+
addColPrefix: config.columns[colKeys].prefix,
|
|
106
|
+
addColSuffix: config.columns[colKeys].suffix,
|
|
107
|
+
addColRoundTo: config.columns[colKeys].roundToPlace ? config.columns[colKeys].roundToPlace : '',
|
|
108
|
+
addColCommas: config.columns[colKeys].commas
|
|
109
|
+
}
|
|
110
|
+
let closestValue = null
|
|
102
111
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
112
|
+
if (config.visualizationType === 'Pie') {
|
|
113
|
+
closestValue = arc?.data[colVals.name]
|
|
114
|
+
} else {
|
|
115
|
+
closestValue = resolvedScaleValues[0][colVals.name]
|
|
106
116
|
}
|
|
107
117
|
|
|
108
|
-
const
|
|
109
|
-
tooltipItems.push([config.xAxis.dataKey, getClosestYValue(y)])
|
|
118
|
+
const formattedValue = formatColNumber(closestValue, 'left', true, config, formattingParams)
|
|
110
119
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
return tooltipItems
|
|
120
|
+
if (colVals.tooltips) {
|
|
121
|
+
columnsWithTooltips.push([colVals.label, formattedValue])
|
|
122
|
+
}
|
|
115
123
|
}
|
|
124
|
+
const additionalTooltipItems = []
|
|
125
|
+
|
|
126
|
+
columnsWithTooltips.forEach(columnData => {
|
|
127
|
+
additionalTooltipItems.push([columnData[0], columnData[1]])
|
|
128
|
+
})
|
|
116
129
|
|
|
117
130
|
if (visualizationType === 'Pie') {
|
|
118
|
-
|
|
131
|
+
tooltipItems.push(
|
|
132
|
+
// ignore
|
|
119
133
|
[config.xAxis.dataKey, pieChartData],
|
|
120
134
|
[config.runtime.yAxis.dataKey, formatNumber(arc?.data[config.runtime.yAxis.dataKey])],
|
|
121
135
|
['Percent', `${Math.round((((arc?.endAngle - arc?.startAngle) * 180) / Math.PI / 360) * 100) + '%'}`]
|
|
122
|
-
|
|
136
|
+
)
|
|
137
|
+
}
|
|
138
|
+
if (visualizationType === 'Forest Plot') {
|
|
139
|
+
tooltipItems.push([config.xAxis.dataKey, getClosestYValue(y)])
|
|
123
140
|
}
|
|
124
141
|
|
|
125
|
-
|
|
126
|
-
.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
142
|
+
if (visualizationType !== 'Pie' && visualizationType !== 'Forest Plot') {
|
|
143
|
+
tooltipItems.push(
|
|
144
|
+
...getIncludedTooltipSeries()
|
|
145
|
+
?.filter(Boolean)
|
|
146
|
+
.flatMap(seriesKey => {
|
|
147
|
+
const formattedValue = seriesKey === config.xAxis.dataKey ? resolvedScaleValues[0][seriesKey] : formatNumber(resolvedScaleValues[0][seriesKey], getAxisPosition(seriesKey))
|
|
148
|
+
return resolvedScaleValues[0][seriesKey] ? [[seriesKey, formattedValue]] : []
|
|
149
|
+
})
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return [...tooltipItems, ...additionalTooltipItems]
|
|
130
154
|
}
|
|
131
155
|
|
|
132
156
|
// Returns an array of arrays.
|
|
@@ -253,9 +277,13 @@ export const useTooltip = props => {
|
|
|
253
277
|
if (!x) throw new Error('COVE: no x value in handleTooltipClick.')
|
|
254
278
|
let closestXScaleValue = getXValueFromCoordinate(x)
|
|
255
279
|
if (!closestXScaleValue) throw new Error('COVE: no closest x scale value in handleTooltipClick')
|
|
256
|
-
let datum = config.data
|
|
280
|
+
let datum = config.data?.filter(item => item[config.xAxis.dataKey] === closestXScaleValue)
|
|
257
281
|
|
|
258
|
-
if (
|
|
282
|
+
if (!datum[0]) {
|
|
283
|
+
throw new Error(`COVE: no data found matching the closest xScale value: ${closestXScaleValue}`)
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
if (setSharedFilter && config?.uid && datum?.[0]) {
|
|
259
287
|
setSharedFilter(config.uid, datum[0])
|
|
260
288
|
}
|
|
261
289
|
} catch (e) {
|
|
@@ -328,7 +356,7 @@ export const useTooltip = props => {
|
|
|
328
356
|
if (!config.dashboard) {
|
|
329
357
|
switch (visualizationType) {
|
|
330
358
|
case 'Combo':
|
|
331
|
-
standardLoopItems = [runtime.xAxis.dataKey, ...runtime?.seriesKeys, ...
|
|
359
|
+
standardLoopItems = [runtime.xAxis.dataKey, ...runtime?.seriesKeys, ...ciItems]
|
|
332
360
|
break
|
|
333
361
|
case 'Forecasting':
|
|
334
362
|
standardLoopItems = [runtime.xAxis.dataKey, ...stageColumns, ...ciItems]
|
|
@@ -346,7 +374,6 @@ export const useTooltip = props => {
|
|
|
346
374
|
standardLoopItems = [runtime.xAxis.dataKey, ...runtime?.seriesKeys]
|
|
347
375
|
default:
|
|
348
376
|
throw new Error('No visualization type found in handleTooltipMouseOver')
|
|
349
|
-
break
|
|
350
377
|
}
|
|
351
378
|
}
|
|
352
379
|
|
|
@@ -403,7 +430,7 @@ export const useTooltip = props => {
|
|
|
403
430
|
if (key === config.xAxis.dataKey) return <li className='tooltip-heading'>{`${capitalize(config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ` : '')} ${config.xAxis.type === 'date' ? value : value}`}</li>
|
|
404
431
|
|
|
405
432
|
// TOOLTIP BODY
|
|
406
|
-
return <li className='tooltip-body'>{`${getSeriesNameFromLabel(key)}: ${
|
|
433
|
+
return <li className='tooltip-body'>{`${getSeriesNameFromLabel(key)}: ${value}`}</li>
|
|
407
434
|
}
|
|
408
435
|
|
|
409
436
|
return {
|
package/src/scss/main.scss
CHANGED
|
@@ -74,34 +74,6 @@
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
.chart-title {
|
|
78
|
-
position: relative;
|
|
79
|
-
padding: 0.6em 0.8em;
|
|
80
|
-
margin: 0;
|
|
81
|
-
color: #fff;
|
|
82
|
-
font-size: 1.1em;
|
|
83
|
-
border-bottom-width: 3px;
|
|
84
|
-
border-bottom-style: solid;
|
|
85
|
-
|
|
86
|
-
border-top-left-radius: 3px;
|
|
87
|
-
border-top-right-radius: 3px;
|
|
88
|
-
|
|
89
|
-
em {
|
|
90
|
-
font-style: italic;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
strong {
|
|
94
|
-
font-weight: bold;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
&:not(:empty) {
|
|
98
|
-
margin: 0 0 1rem 0 !important;
|
|
99
|
-
padding: 0.6em 0.8em;
|
|
100
|
-
border-bottom-width: 3px;
|
|
101
|
-
border-bottom-style: solid;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
77
|
.chart-description {
|
|
106
78
|
margin-bottom: 20px;
|
|
107
79
|
}
|
|
@@ -560,14 +532,14 @@
|
|
|
560
532
|
|
|
561
533
|
&.animated {
|
|
562
534
|
.vertical rect,
|
|
563
|
-
.vertical foreignObject {
|
|
535
|
+
.vertical foreignObject div {
|
|
564
536
|
opacity: 0;
|
|
565
537
|
animation: growBar 0.5s linear forwards;
|
|
566
538
|
animation-play-state: paused;
|
|
567
539
|
}
|
|
568
540
|
|
|
569
541
|
.horizontal rect,
|
|
570
|
-
.horizontal foreignObject {
|
|
542
|
+
.horizontal foreignObject div {
|
|
571
543
|
opacity: 0;
|
|
572
544
|
animation: growBarH 0.5s linear forwards;
|
|
573
545
|
animation-play-state: paused;
|
|
@@ -575,7 +547,7 @@
|
|
|
575
547
|
|
|
576
548
|
&.animate {
|
|
577
549
|
rect,
|
|
578
|
-
foreignObject {
|
|
550
|
+
foreignObject div {
|
|
579
551
|
animation-play-state: running;
|
|
580
552
|
}
|
|
581
553
|
}
|
|
@@ -674,10 +646,6 @@
|
|
|
674
646
|
background: transparent;
|
|
675
647
|
}
|
|
676
648
|
|
|
677
|
-
.chart-title:not(:empty) {
|
|
678
|
-
margin-bottom: 0 !important;
|
|
679
|
-
}
|
|
680
|
-
|
|
681
649
|
.cove-component__content .chart-container {
|
|
682
650
|
padding: 1em;
|
|
683
651
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { type ForestPlotConfigSettings } from './ForestPlot'
|
|
2
|
+
|
|
3
|
+
export type ChartColumns = {
|
|
4
|
+
[key: string]: {
|
|
5
|
+
label: string
|
|
6
|
+
dataTable: boolean
|
|
7
|
+
tooltips: boolean
|
|
8
|
+
prefix: string
|
|
9
|
+
suffix: string
|
|
10
|
+
forestPlot: boolean
|
|
11
|
+
startingPoint: string
|
|
12
|
+
forestPlotAlignRight: boolean
|
|
13
|
+
name?: string
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
type Series = {
|
|
18
|
+
dataKey: string
|
|
19
|
+
axis: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
type AllChartsConfig = {
|
|
23
|
+
columns: ChartColumns
|
|
24
|
+
forestPlot: ForestPlotConfigSettings
|
|
25
|
+
isLollipopChart: boolean
|
|
26
|
+
legend: {
|
|
27
|
+
behavior: 'highlight' | unknown
|
|
28
|
+
}
|
|
29
|
+
orientation: 'vertical' | 'horizontal'
|
|
30
|
+
runtime: {}
|
|
31
|
+
series: Series[]
|
|
32
|
+
useLogScale: boolean
|
|
33
|
+
visualizationType: 'Area Chart' | 'Bar' | 'Deviation Bar' | 'Forest Plot' | 'Paired Bar' | 'Scatter Plot' | 'Spark Line'
|
|
34
|
+
xScale: Function
|
|
35
|
+
yScale: Function
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export type LineChartConfig = {
|
|
39
|
+
visualizationType: 'Line'
|
|
40
|
+
lineDatapointStyle: 'hidden' | 'always show' | 'hover'
|
|
41
|
+
} & AllCharts
|
|
42
|
+
|
|
43
|
+
export type ChartConfig = LineChartConfig | AllChartsConfig
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type ChartConfig } from './ChartConfig'
|
|
2
|
+
|
|
3
|
+
// Line Chart Specific Context
|
|
4
|
+
type LineChartContext = {
|
|
5
|
+
colorScale: Function
|
|
6
|
+
config: ChartConfig
|
|
7
|
+
dimensions: [screenWidth: number, screenHeight: number]
|
|
8
|
+
formatDate: Function
|
|
9
|
+
formatNumber: Function
|
|
10
|
+
handleLineType: Function
|
|
11
|
+
isNumber: unknown
|
|
12
|
+
parseDate: Function
|
|
13
|
+
rawData: Object[]
|
|
14
|
+
seriesHighlight: String[]
|
|
15
|
+
tableData: Object[]
|
|
16
|
+
transformedData: Object[]
|
|
17
|
+
updateConfig: Function
|
|
18
|
+
visualizationType: 'Line'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type ChartContext =
|
|
22
|
+
| LineChartContext
|
|
23
|
+
| {
|
|
24
|
+
colorScale?: Function
|
|
25
|
+
config?: ChartConfig
|
|
26
|
+
dimensions: [screenWidth: number, screenHeight: number]
|
|
27
|
+
|
|
28
|
+
formatDate?: Function
|
|
29
|
+
formatNumber?: Function
|
|
30
|
+
handleLineType?: Function
|
|
31
|
+
isNumber?: boolean
|
|
32
|
+
parseDate?: Function
|
|
33
|
+
rawData?: Object[]
|
|
34
|
+
seriesHighlight?: String[]
|
|
35
|
+
tableData?: Object[]
|
|
36
|
+
transformedData?: Object[]
|
|
37
|
+
updateConfig?: Function
|
|
38
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { type Color } from '@cdc/core/types/Color'
|
|
2
|
+
|
|
3
|
+
export type ForestPlotConfigSettings = {
|
|
4
|
+
colors: {
|
|
5
|
+
line: Color // color of line of effect
|
|
6
|
+
shape: Color // color for effect estimate shape
|
|
7
|
+
}
|
|
8
|
+
// description - appears below the study column.
|
|
9
|
+
description: {
|
|
10
|
+
show: boolean
|
|
11
|
+
text: string
|
|
12
|
+
location: number
|
|
13
|
+
}
|
|
14
|
+
// effect estimates
|
|
15
|
+
estimateField: string // column chose for the effect estimate
|
|
16
|
+
estimateRadius: string
|
|
17
|
+
hideDateCategoryCol: boolean
|
|
18
|
+
leftWidthOffset: number
|
|
19
|
+
lineOfNoEffect: {
|
|
20
|
+
show: boolean
|
|
21
|
+
}
|
|
22
|
+
lower: string
|
|
23
|
+
upper: string
|
|
24
|
+
// type - determines the type of scale we're using, including the position of line of effect (0 or 1)
|
|
25
|
+
type: 'Linear' | 'Logarithmic'
|
|
26
|
+
pooledResult: {
|
|
27
|
+
diamondHeight: number
|
|
28
|
+
column: string
|
|
29
|
+
}
|
|
30
|
+
// rowHeight - height of study
|
|
31
|
+
rowHeight: number
|
|
32
|
+
// radius - scaling for effect estimates
|
|
33
|
+
radius: {
|
|
34
|
+
min: number
|
|
35
|
+
max: number
|
|
36
|
+
/** @deprecated - moved to estimateField due to duplication */
|
|
37
|
+
scalingColumn: string
|
|
38
|
+
}
|
|
39
|
+
/** @deprecated - moved to pooledResult */
|
|
40
|
+
regression: {
|
|
41
|
+
lower: number
|
|
42
|
+
upper: number
|
|
43
|
+
estimateField: number
|
|
44
|
+
}
|
|
45
|
+
result: {
|
|
46
|
+
show: boolean
|
|
47
|
+
text: string
|
|
48
|
+
location: number
|
|
49
|
+
}
|
|
50
|
+
rightWidthOffset: number
|
|
51
|
+
shape: string
|
|
52
|
+
startAt: number
|
|
53
|
+
title: string // centered title above the chart
|
|
54
|
+
|
|
55
|
+
/** @deprecated - moved to lineOfNoEffect*/
|
|
56
|
+
showZeroLine: boolean
|
|
57
|
+
// labels under chart
|
|
58
|
+
leftLabel: string
|
|
59
|
+
rightLabel: string
|
|
60
|
+
}
|