@cdc/chart 4.23.11 → 4.24.2
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 +35740 -35027
- package/examples/feature/bar/additional-column-tooltip.json +446 -0
- package/examples/feature/bar/tall-data.json +98 -0
- package/examples/feature/forest-plot/forest-plot.json +63 -19
- package/examples/feature/forest-plot/linear.json +52 -3
- package/examples/feature/forest-plot/log.json +26 -0
- package/examples/feature/forest-plot/logarithmic.json +0 -35
- package/examples/feature/line/line-chart-preliminary.json +393 -0
- package/examples/feature/regions/index.json +9 -5
- package/examples/feature/scatterplot/scatterplot.json +272 -33
- package/index.html +10 -8
- package/package.json +2 -2
- package/src/CdcChart.tsx +70 -234
- package/src/ConfigContext.tsx +6 -0
- package/src/_stories/ChartEditor.stories.tsx +22 -0
- package/src/_stories/ChartLine.preliminary.tsx +19 -0
- package/src/_stories/_mock/pie_config.json +192 -0
- package/src/_stories/_mock/pie_data.json +218 -0
- package/src/_stories/_mock/preliminary_mock.json +346 -0
- package/src/components/{AreaChart.Stacked.jsx → AreaChart/components/AreaChart.Stacked.jsx} +2 -2
- package/src/components/{AreaChart.jsx → AreaChart/components/AreaChart.jsx} +2 -26
- package/src/components/AreaChart/index.tsx +4 -0
- package/src/components/{BarChart.Horizontal.tsx → BarChart/components/BarChart.Horizontal.tsx} +8 -8
- package/src/components/{BarChart.StackedHorizontal.tsx → BarChart/components/BarChart.StackedHorizontal.tsx} +37 -7
- package/src/components/BarChart/components/BarChart.StackedVertical.tsx +108 -0
- package/src/components/{BarChart.Vertical.tsx → BarChart/components/BarChart.Vertical.tsx} +53 -70
- package/src/components/BarChart/components/BarChart.jsx +39 -0
- package/src/components/{BarChartType.jsx → BarChart/components/BarChartType.jsx} +0 -2
- package/src/components/BarChart/components/context.tsx +13 -0
- package/src/components/BarChart/index.tsx +3 -0
- package/src/components/{BoxPlot.jsx → BoxPlot/BoxPlot.jsx} +10 -9
- package/src/components/BoxPlot/index.tsx +3 -0
- package/src/components/EditorPanel/EditorPanel.tsx +2776 -0
- package/src/components/EditorPanel/EditorPanelContext.ts +40 -0
- package/src/components/EditorPanel/components/PanelProps.ts +3 -0
- package/src/components/EditorPanel/components/Panels/Panel.BoxPlot.tsx +148 -0
- package/src/components/{ForestPlotSettings.jsx → EditorPanel/components/Panels/Panel.ForestPlotSettings.tsx} +97 -167
- package/src/components/EditorPanel/components/Panels/Panel.General.tsx +160 -0
- package/src/components/EditorPanel/components/Panels/Panel.Regions.tsx +168 -0
- package/src/components/{Series.jsx → EditorPanel/components/Panels/Panel.Series.tsx} +4 -4
- package/src/components/EditorPanel/components/Panels/Panel.Visual.tsx +297 -0
- package/src/components/EditorPanel/components/Panels/index.tsx +17 -0
- package/src/components/EditorPanel/components/panels.scss +72 -0
- package/src/components/EditorPanel/editor-panel.scss +739 -0
- package/src/components/EditorPanel/index.tsx +3 -0
- package/src/{hooks → components/EditorPanel}/useEditorPermissions.js +34 -2
- package/src/components/{Forecasting.jsx → Forecasting/Forecasting.jsx} +1 -1
- package/src/components/Forecasting/index.tsx +3 -0
- package/src/components/ForestPlot/ForestPlot.tsx +254 -0
- package/src/components/ForestPlot/ForestPlotProps.ts +7 -0
- package/src/components/ForestPlot/index.tsx +1 -209
- package/src/components/Legend/Legend.Component.tsx +199 -0
- package/src/components/Legend/Legend.tsx +28 -0
- package/src/components/Legend/helpers/createFormatLabels.tsx +140 -0
- package/src/components/Legend/index.tsx +3 -0
- package/src/components/LineChart/LineChartProps.ts +29 -0
- package/src/components/LineChart/components/LineChart.Circle.tsx +147 -0
- package/src/components/LineChart/helpers.ts +45 -0
- package/src/components/LineChart/index.tsx +111 -23
- package/src/components/LinearChart.jsx +55 -72
- package/src/components/PairedBarChart.jsx +4 -2
- package/src/components/{PieChart.jsx → PieChart/PieChart.tsx} +93 -31
- package/src/components/PieChart/index.tsx +3 -0
- package/src/components/Regions/components/Regions.tsx +144 -0
- package/src/components/Regions/index.tsx +3 -0
- package/src/components/{ScatterPlot.jsx → ScatterPlot/ScatterPlot.jsx} +3 -3
- package/src/components/ScatterPlot/index.tsx +3 -0
- package/src/components/{SparkLine.jsx → Sparkline/SparkLine.jsx} +2 -2
- package/src/components/Sparkline/index.tsx +3 -0
- package/src/data/initial-state.js +10 -8
- package/src/helpers/abbreviateNumber.ts +17 -0
- package/src/helpers/computeMarginBottom.ts +55 -0
- package/src/helpers/filterData.ts +18 -0
- package/src/helpers/generateColorsArray.ts +8 -0
- package/src/helpers/getQuartiles.ts +30 -0
- package/src/helpers/handleChartAriaLabels.ts +19 -0
- package/src/helpers/handleLineType.ts +18 -0
- package/src/helpers/lineOptions.ts +18 -0
- package/src/helpers/sort.ts +7 -0
- package/src/helpers/tests/computeMarginBottom.test.ts +20 -0
- package/src/hooks/useBarChart.js +7 -6
- package/src/hooks/useHighlightedBars.js +1 -1
- package/src/hooks/useMinMax.ts +3 -3
- package/src/hooks/useScales.ts +19 -6
- package/src/hooks/{useTooltip.jsx → useTooltip.tsx} +31 -25
- package/src/scss/main.scss +0 -3
- package/src/types/ChartConfig.ts +167 -23
- package/src/types/ChartContext.ts +34 -12
- package/src/types/ForestPlot.ts +7 -14
- package/src/types/Label.ts +7 -0
- package/examples/feature/scatterplot/scatterplot-continuous.csv +0 -17
- package/src/ConfigContext.jsx +0 -5
- package/src/components/BarChart.StackedVertical.tsx +0 -91
- package/src/components/BarChart.jsx +0 -30
- package/src/components/EditorPanel.jsx +0 -3356
- package/src/components/ForestPlot/Readme.md +0 -0
- package/src/components/Legend.jsx +0 -310
- package/src/components/LineChart/LineChart.Circle.tsx +0 -105
- package/src/scss/LinearChart.scss +0 -0
- package/src/scss/editor-panel.scss +0 -745
- package/src/scss/legend.scss +0 -206
- package/src/scss/mixins.scss +0 -0
- package/src/scss/variables.scss +0 -1
- package/src/types/ChartProps.ts +0 -7
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ChartConfig, Legend } from '../../types/ChartConfig'
|
|
2
|
+
import { computeMarginBottom } from '../computeMarginBottom'
|
|
3
|
+
|
|
4
|
+
describe('computeMarginBottom', () => {
|
|
5
|
+
it('should return correct value', () => {
|
|
6
|
+
const config = {
|
|
7
|
+
orientation: 'horizontal',
|
|
8
|
+
xAxis: { labelOffset: '10' },
|
|
9
|
+
yAxis: { label: null },
|
|
10
|
+
brush: { active: false },
|
|
11
|
+
isResponsiveTicks: true,
|
|
12
|
+
dynamicMarginTop: 20
|
|
13
|
+
}
|
|
14
|
+
const legend = { position: 'top' }
|
|
15
|
+
const currentViewport = 'md'
|
|
16
|
+
expect(computeMarginBottom(config as unknown as ChartConfig, legend as Legend, currentViewport)).toBe('0px')
|
|
17
|
+
config.yAxis.label = 'label'
|
|
18
|
+
expect(computeMarginBottom(config as unknown as ChartConfig, legend as Legend, currentViewport)).toBe('40px')
|
|
19
|
+
})
|
|
20
|
+
})
|
package/src/hooks/useBarChart.js
CHANGED
|
@@ -184,7 +184,7 @@ export const useBarChart = () => {
|
|
|
184
184
|
return 0
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
-
const getAdditionalColumn = xAxisDataValue => {
|
|
187
|
+
const getAdditionalColumn = (series, xAxisDataValue) => {
|
|
188
188
|
if (!xAxisDataValue) return ''
|
|
189
189
|
const columns = config.columns
|
|
190
190
|
const columnsWithTooltips = []
|
|
@@ -193,7 +193,8 @@ export const useBarChart = () => {
|
|
|
193
193
|
tableData.find(d => {
|
|
194
194
|
return d[config.xAxis.dataKey] === xAxisDataValue
|
|
195
195
|
}) || {}
|
|
196
|
-
|
|
196
|
+
Object.keys(columns).forEach(colKeys => {
|
|
197
|
+
if(series && config.columns[colKeys].series && config.columns[colKeys].series !== series) return
|
|
197
198
|
const formattingParams = {
|
|
198
199
|
addColPrefix: config.columns[colKeys].prefix,
|
|
199
200
|
addColSuffix: config.columns[colKeys].suffix,
|
|
@@ -201,11 +202,11 @@ export const useBarChart = () => {
|
|
|
201
202
|
addColCommas: config.columns[colKeys].commas
|
|
202
203
|
}
|
|
203
204
|
|
|
204
|
-
const formattedValue = formatColNumber(closestVal[
|
|
205
|
-
if (
|
|
206
|
-
columnsWithTooltips.push([
|
|
205
|
+
const formattedValue = formatColNumber(closestVal[config.columns[colKeys].name], 'left', true, config, formattingParams)
|
|
206
|
+
if (config.columns[colKeys].tooltips) {
|
|
207
|
+
columnsWithTooltips.push([config.columns[colKeys].label, formattedValue])
|
|
207
208
|
}
|
|
208
|
-
}
|
|
209
|
+
})
|
|
209
210
|
columnsWithTooltips.forEach(columnData => {
|
|
210
211
|
additionalTooltipItems += `${columnData[0]} : ${columnData[1]} <br/>`
|
|
211
212
|
})
|
|
@@ -127,7 +127,7 @@ export const useHighlightedBars = (config, updateConfig) => {
|
|
|
127
127
|
*/
|
|
128
128
|
HighLightedBarUtils.findDuplicates = arr => {
|
|
129
129
|
const duplicates = {}
|
|
130
|
-
const result = arr
|
|
130
|
+
const result = arr?.filter(obj => {
|
|
131
131
|
const { legendLabel } = obj
|
|
132
132
|
if (!duplicates[legendLabel]) {
|
|
133
133
|
duplicates[legendLabel] = true
|
package/src/hooks/useMinMax.ts
CHANGED
|
@@ -181,10 +181,10 @@ const useMinMax = ({ config, minValue, maxValue, existPositiveValue, data, isAll
|
|
|
181
181
|
if (config.yAxis.enablePadding) {
|
|
182
182
|
if (min < 0) {
|
|
183
183
|
// sets with negative data need more padding on the max
|
|
184
|
-
max *= 1.2
|
|
185
|
-
min *= 1.2
|
|
184
|
+
max *= 1 + (config.yAxis.scalePadding * 2) / 100
|
|
185
|
+
min *= 1 + (config.yAxis.scalePadding * 2) / 100
|
|
186
186
|
} else {
|
|
187
|
-
max *= 1.
|
|
187
|
+
max *= 1 + config.yAxis.scalePadding / 100
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
|
package/src/hooks/useScales.ts
CHANGED
|
@@ -56,21 +56,25 @@ const useScales = (properties: useScaleProps) => {
|
|
|
56
56
|
|
|
57
57
|
// handle Vertical bars
|
|
58
58
|
if (!isHorizontal) {
|
|
59
|
-
xScaleBrush = composeScalePoint(xAxisDataKeysMapped, [0, xMax],
|
|
60
|
-
xScale =
|
|
61
|
-
xScale.type = scaleTypes.POINT
|
|
59
|
+
xScaleBrush = composeScalePoint(xAxisDataKeysMapped, [0, xMax], .5)
|
|
60
|
+
xScale = composeScaleBand(xAxisDataMapped, [0, xMax], 1 - config.barThickness)
|
|
62
61
|
yScale = composeYScale(properties)
|
|
63
|
-
seriesScale =
|
|
62
|
+
seriesScale = composeScaleBand(seriesDomain, [0, xScale.bandwidth()], 0)
|
|
64
63
|
}
|
|
65
64
|
|
|
66
65
|
// handle Area chart
|
|
67
66
|
if (config.xAxis.type === 'date' && config.xAxis.sortDates) {
|
|
67
|
+
let xAxisMin = Math.min(...xAxisDataMapped)
|
|
68
|
+
let xAxisMax = Math.max(...xAxisDataMapped)
|
|
69
|
+
xAxisMin -= (config.xAxis.padding ? config.xAxis.padding * 0.01 : 0) * (xAxisMax - xAxisMin)
|
|
70
|
+
xAxisMax += (config.xAxis.padding ? config.xAxis.padding * 0.01 : 0) * (xAxisMax - xAxisMin)
|
|
68
71
|
xScale = scaleTime({
|
|
69
|
-
domain: [
|
|
72
|
+
domain: [xAxisMin, xAxisMax],
|
|
70
73
|
range: [0, xMax]
|
|
71
74
|
})
|
|
72
75
|
xScaleBrush = xScale
|
|
73
76
|
xScale.type = scaleTypes.LINEAR
|
|
77
|
+
seriesScale = composeScaleBand(seriesDomain, [0, config.barThickness * (xMax)], 0)
|
|
74
78
|
}
|
|
75
79
|
|
|
76
80
|
// handle Deviation bar
|
|
@@ -190,7 +194,7 @@ const useScales = (properties: useScaleProps) => {
|
|
|
190
194
|
if (config.forestPlot.type === 'Linear') {
|
|
191
195
|
xScale = scaleLinear({
|
|
192
196
|
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,
|
|
197
|
+
range: [leftWidthOffset, dimensions[0] - rightWidthOffset]
|
|
194
198
|
})
|
|
195
199
|
xScale.type = scaleTypes.LINEAR
|
|
196
200
|
}
|
|
@@ -284,3 +288,12 @@ const composeScalePoint = (domain, range, padding = 0) => {
|
|
|
284
288
|
type: 'point'
|
|
285
289
|
})
|
|
286
290
|
}
|
|
291
|
+
|
|
292
|
+
const composeScaleBand = (domain, range, padding = 0) => {
|
|
293
|
+
return scaleBand({
|
|
294
|
+
domain: domain,
|
|
295
|
+
range: range,
|
|
296
|
+
padding: padding,
|
|
297
|
+
type: 'band'
|
|
298
|
+
})
|
|
299
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useContext } from 'react'
|
|
2
2
|
import ConfigContext from '../ConfigContext'
|
|
3
|
-
import {
|
|
3
|
+
import { type ChartContext } from '../types/ChartContext'
|
|
4
4
|
|
|
5
5
|
// third party
|
|
6
6
|
import { localPoint } from '@visx/event'
|
|
@@ -11,7 +11,7 @@ const transform = new DataTransform()
|
|
|
11
11
|
import { formatNumber as formatColNumber } from '@cdc/core/helpers/cove/number'
|
|
12
12
|
|
|
13
13
|
export const useTooltip = props => {
|
|
14
|
-
const { tableData, config, formatNumber, capitalize, formatDate, parseDate, setSharedFilter } = useContext(ConfigContext)
|
|
14
|
+
const { tableData, config, formatNumber, capitalize, formatDate, formatTooltipsDate, parseDate, setSharedFilter } = useContext<ChartContext>(ConfigContext)
|
|
15
15
|
const { xScale, yScale, showTooltip, hideTooltip } = props
|
|
16
16
|
const { xAxis, visualizationType, orientation, yAxis, runtime } = config
|
|
17
17
|
const data = transform.applySuppression(tableData, config.suppressedData)
|
|
@@ -82,13 +82,10 @@ export const useTooltip = props => {
|
|
|
82
82
|
includedSeries.push(...getColumnNames(config.columns))
|
|
83
83
|
|
|
84
84
|
const yScaleValues = getYScaleValues(closestXScaleValue, includedSeries)
|
|
85
|
-
|
|
86
85
|
const xScaleValues = data.filter(d => d[xAxis.dataKey] === getClosestYValue(y))
|
|
87
86
|
|
|
88
87
|
const resolvedScaleValues = orientation === 'vertical' ? yScaleValues : xScaleValues
|
|
89
88
|
|
|
90
|
-
// const forestPlotXValue = visualizationType === 'Forest Plot' ? data?.filter(d => d[xAxis.dataKey] === getClosestYValue(y))?.[0]?.[config.forestPlot.estimateField] : null
|
|
91
|
-
|
|
92
89
|
const getAxisPosition = seriesKey => {
|
|
93
90
|
const seriesObj = config.series.filter(s => s.dataKey === seriesKey)[0]
|
|
94
91
|
const position = seriesObj?.axis ? String(seriesObj.axis).toLowerCase() : 'left'
|
|
@@ -112,7 +109,7 @@ export const useTooltip = props => {
|
|
|
112
109
|
if (config.visualizationType === 'Pie') {
|
|
113
110
|
closestValue = arc?.data[colVals.name]
|
|
114
111
|
} else {
|
|
115
|
-
closestValue = resolvedScaleValues[0][colVals.name]
|
|
112
|
+
closestValue = resolvedScaleValues[0]?.[colVals.name]
|
|
116
113
|
}
|
|
117
114
|
|
|
118
115
|
const formattedValue = formatColNumber(closestValue, 'left', true, config, formattingParams)
|
|
@@ -135,6 +132,7 @@ export const useTooltip = props => {
|
|
|
135
132
|
['Percent', `${Math.round((((arc?.endAngle - arc?.startAngle) * 180) / Math.PI / 360) * 100) + '%'}`]
|
|
136
133
|
)
|
|
137
134
|
}
|
|
135
|
+
|
|
138
136
|
if (visualizationType === 'Forest Plot') {
|
|
139
137
|
tooltipItems.push([config.xAxis.dataKey, getClosestYValue(y)])
|
|
140
138
|
}
|
|
@@ -143,9 +141,9 @@ export const useTooltip = props => {
|
|
|
143
141
|
tooltipItems.push(
|
|
144
142
|
...getIncludedTooltipSeries()
|
|
145
143
|
?.filter(Boolean)
|
|
146
|
-
|
|
147
|
-
const formattedValue = seriesKey === config.xAxis.dataKey ? resolvedScaleValues[0][seriesKey] : formatNumber(resolvedScaleValues[0][seriesKey], getAxisPosition(seriesKey))
|
|
148
|
-
return resolvedScaleValues[0][seriesKey] ? [[seriesKey, formattedValue]] : []
|
|
144
|
+
?.flatMap(seriesKey => {
|
|
145
|
+
const formattedValue = seriesKey === config.xAxis.dataKey ? resolvedScaleValues[0]?.[seriesKey] : formatNumber(resolvedScaleValues[0]?.[seriesKey], getAxisPosition(seriesKey))
|
|
146
|
+
return resolvedScaleValues?.[0]?.[seriesKey] ? [[seriesKey, formattedValue, getAxisPosition(seriesKey)]] : []
|
|
149
147
|
})
|
|
150
148
|
)
|
|
151
149
|
}
|
|
@@ -204,9 +202,11 @@ export const useTooltip = props => {
|
|
|
204
202
|
* @function getXValueFromCoordinate
|
|
205
203
|
* @returns {String} - the closest x value to the cursor position
|
|
206
204
|
*/
|
|
207
|
-
const getXValueFromCoordinate = x => {
|
|
205
|
+
const getXValueFromCoordinate = (x, isClick = false) => {
|
|
208
206
|
if (visualizationType === 'Pie') return
|
|
209
207
|
if (orientation === 'horizontal') return
|
|
208
|
+
|
|
209
|
+
// Check the type of x equal to point or if the type of xAxis is equal to continuous or date
|
|
210
210
|
if (xScale.type === 'point' || xAxis.type === 'continuous' || xAxis.type === 'date') {
|
|
211
211
|
// Find the closest x value by calculating the minimum distance
|
|
212
212
|
let closestX = null
|
|
@@ -215,21 +215,24 @@ export const useTooltip = props => {
|
|
|
215
215
|
|
|
216
216
|
data.forEach(d => {
|
|
217
217
|
const xPosition = xAxis.type === 'date' ? xScale(parseDate(d[xAxis.dataKey])) : xScale(d[xAxis.dataKey])
|
|
218
|
-
|
|
218
|
+
let bwOffset = config.barHeight
|
|
219
|
+
const distance = Math.abs(Number(xPosition - offset + (isClick ? bwOffset * 2 : 0)))
|
|
219
220
|
|
|
220
|
-
if (distance
|
|
221
|
+
if (distance <= minDistance) {
|
|
221
222
|
minDistance = distance
|
|
222
|
-
closestX = xAxis.type === 'date' ?
|
|
223
|
+
closestX = xAxis.type === 'date' ? d[xAxis.dataKey] : d[xAxis.dataKey]
|
|
223
224
|
}
|
|
224
225
|
})
|
|
225
226
|
return closestX
|
|
226
227
|
}
|
|
227
228
|
|
|
228
229
|
if (config.xAxis.type === 'categorical' || (visualizationType === 'Combo' && orientation !== 'horizontal' && visualizationType !== 'Forest Plot')) {
|
|
229
|
-
let
|
|
230
|
+
let range = xScale.range()[1] - xScale.range()[0]
|
|
231
|
+
let eachBand = range / (xScale.domain().length + 1)
|
|
232
|
+
|
|
230
233
|
let numerator = x
|
|
231
|
-
const index = Math.floor(Number(numerator) / eachBand)
|
|
232
|
-
return xScale.domain()[index
|
|
234
|
+
const index = Math.floor((Number(numerator) - eachBand / 2) / eachBand)
|
|
235
|
+
return xScale.domain()[index] // fixes off by 1 error
|
|
233
236
|
}
|
|
234
237
|
|
|
235
238
|
if (config.xAxis.type === 'date' && visualizationType !== 'Combo' && orientation !== 'horizontal') {
|
|
@@ -250,7 +253,6 @@ export const useTooltip = props => {
|
|
|
250
253
|
const yPositionOnPlot = visualizationType !== 'Forest Plot' ? yScale(d[config.xAxis.dataKey]) : yScale(index)
|
|
251
254
|
|
|
252
255
|
const distance = Math.abs(yPositionOnPlot - yPosition)
|
|
253
|
-
|
|
254
256
|
if (distance < minDistance) {
|
|
255
257
|
minDistance = distance
|
|
256
258
|
closestYValue = key ? d[key] : d[config.xAxis.dataKey]
|
|
@@ -275,9 +277,14 @@ export const useTooltip = props => {
|
|
|
275
277
|
const eventSvgCoords = localPoint(e)
|
|
276
278
|
const { x } = eventSvgCoords
|
|
277
279
|
if (!x) throw new Error('COVE: no x value in handleTooltipClick.')
|
|
278
|
-
let closestXScaleValue = getXValueFromCoordinate(x)
|
|
279
|
-
if (!closestXScaleValue) throw new Error('COVE: no closest x scale value in handleTooltipClick')
|
|
280
|
+
let closestXScaleValue = getXValueFromCoordinate(x, true)
|
|
280
281
|
let datum = config.data?.filter(item => item[config.xAxis.dataKey] === closestXScaleValue)
|
|
282
|
+
if (!closestXScaleValue) throw new Error('COVE: no closest x scale value in handleTooltipClick')
|
|
283
|
+
if (xAxis.type === 'date' && closestXScaleValue) {
|
|
284
|
+
closestXScaleValue = new Date(closestXScaleValue)
|
|
285
|
+
closestXScaleValue = formatDate(closestXScaleValue)
|
|
286
|
+
datum = config.data?.filter(item => formatDate(new Date(item[config.xAxis.dataKey])) === closestXScaleValue)
|
|
287
|
+
}
|
|
281
288
|
|
|
282
289
|
if (!datum[0]) {
|
|
283
290
|
throw new Error(`COVE: no data found matching the closest xScale value: ${closestXScaleValue}`)
|
|
@@ -300,16 +307,13 @@ export const useTooltip = props => {
|
|
|
300
307
|
*/
|
|
301
308
|
const getYScaleValues = (closestXScaleValue, includedSeries) => {
|
|
302
309
|
try {
|
|
303
|
-
const formattedDate = formatDate(closestXScaleValue)
|
|
304
|
-
|
|
305
310
|
let dataToSearch
|
|
306
311
|
|
|
307
312
|
if (xAxis.type === 'categorical') {
|
|
308
313
|
dataToSearch = data.filter(d => d[xAxis.dataKey] === closestXScaleValue)
|
|
309
314
|
} else {
|
|
310
|
-
dataToSearch = data.filter(d =>
|
|
315
|
+
dataToSearch = data.filter(d => d[xAxis.dataKey] === closestXScaleValue)
|
|
311
316
|
}
|
|
312
|
-
|
|
313
317
|
// Return an empty array if no matching data is found.
|
|
314
318
|
if (!dataToSearch || dataToSearch.length === 0) {
|
|
315
319
|
return []
|
|
@@ -424,10 +428,12 @@ export const useTooltip = props => {
|
|
|
424
428
|
if (key === config.xAxis.dataKey) return <li className='tooltip-heading'>{`${capitalize(config.xAxis.dataKey ? `${config.xAxis.dataKey}: ` : '')} ${config.yAxis.type === 'date' ? formatDate(parseDate(key, false)) : value}`}</li>
|
|
425
429
|
return <li className='tooltip-body'>{`${getSeriesNameFromLabel(key)}: ${formatNumber(value, 'left')}`}</li>
|
|
426
430
|
}
|
|
431
|
+
const formattedDate = config.tooltips.dateDisplayFormat ? formatTooltipsDate(parseDate(value, false)) : formatDate(parseDate(value, false))
|
|
427
432
|
|
|
428
433
|
// TOOLTIP HEADING
|
|
429
|
-
if (visualizationType === 'Bar' && orientation === 'horizontal' && key === config.xAxis.dataKey) return <li className='tooltip-heading'>{`${capitalize(config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ` : '')} ${value}`}</li>
|
|
430
|
-
|
|
434
|
+
if (visualizationType === 'Bar' && orientation === 'horizontal' && key === config.xAxis.dataKey) return <li className='tooltip-heading'>{`${capitalize(config.runtime.yAxis.label ? `${config.runtime.yAxis.label}: ` : '')} ${config.xAxis.type === 'date' ? formattedDate : value}`}</li>
|
|
435
|
+
|
|
436
|
+
if (key === config.xAxis.dataKey) return <li className='tooltip-heading'>{`${capitalize(config.runtime.xAxis.label ? `${config.runtime.xAxis.label}: ` : '')} ${config.xAxis.type === 'date' ? formattedDate : value}`}</li>
|
|
431
437
|
|
|
432
438
|
// TOOLTIP BODY
|
|
433
439
|
return <li className='tooltip-body'>{`${getSeriesNameFromLabel(key)}: ${value}`}</li>
|
package/src/scss/main.scss
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
@import '@cdc/core/styles/base';
|
|
2
2
|
@import '@cdc/core/styles/heading-colors';
|
|
3
|
-
@import 'mixins';
|
|
4
|
-
@import 'variables';
|
|
5
3
|
@import '@cdc/core/styles/v2/themes/color-definitions';
|
|
6
4
|
|
|
7
5
|
.form-container {
|
|
@@ -17,7 +15,6 @@
|
|
|
17
15
|
|
|
18
16
|
.cdc-open-viz-module.type-chart {
|
|
19
17
|
@import 'DataTable';
|
|
20
|
-
@import 'editor-panel';
|
|
21
18
|
|
|
22
19
|
border-radius: 3px;
|
|
23
20
|
|
package/src/types/ChartConfig.ts
CHANGED
|
@@ -1,43 +1,187 @@
|
|
|
1
|
+
import { Axis } from '@cdc/core/types/Axis'
|
|
1
2
|
import { type ForestPlotConfigSettings } from './ForestPlot'
|
|
3
|
+
import { type Column } from '@cdc/core/types/Column'
|
|
4
|
+
import { type Series } from '@cdc/core/types/Series'
|
|
5
|
+
import { Runtime } from '@cdc/core/types/Runtime'
|
|
6
|
+
import { FilterBehavior } from '@cdc/core/types/FilterBehavior'
|
|
7
|
+
import { Table } from '@cdc/core/types/Table'
|
|
8
|
+
import { BoxPlot } from '@cdc/core/types/BoxPlot'
|
|
9
|
+
import { General } from '@cdc/core/types/General'
|
|
2
10
|
|
|
3
|
-
export type ChartColumns =
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
11
|
+
export type ChartColumns = Record<string, Column>
|
|
12
|
+
|
|
13
|
+
type Region = {
|
|
14
|
+
from: string
|
|
15
|
+
to: string
|
|
16
|
+
fromType: 'Previous Days' | 'Fixed Date'
|
|
17
|
+
toType: 'Last Date' | 'Fised Date'
|
|
18
|
+
label: string
|
|
19
|
+
color: string
|
|
20
|
+
background: string
|
|
21
|
+
range: 'Custom' | string
|
|
15
22
|
}
|
|
16
23
|
|
|
17
|
-
type
|
|
18
|
-
|
|
19
|
-
|
|
24
|
+
type DataFormat = {
|
|
25
|
+
abbreviated: boolean
|
|
26
|
+
bottomAbbreviated: boolean
|
|
27
|
+
bottomCommas: boolean
|
|
28
|
+
bottomPrefix: string
|
|
29
|
+
bottomRoundTo: number
|
|
30
|
+
bottomSuffix: string
|
|
31
|
+
commas: boolean
|
|
32
|
+
prefix: string
|
|
33
|
+
rightCommas: boolean
|
|
34
|
+
rightPrefix: string
|
|
35
|
+
rightRoundTo: number
|
|
36
|
+
rightSuffix: string
|
|
37
|
+
roundTo: number
|
|
38
|
+
suffix: string
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
type Exclusions = {
|
|
42
|
+
keys: string[]
|
|
43
|
+
active: boolean
|
|
44
|
+
dateStart: string
|
|
45
|
+
dateEnd: string
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type Filter = {
|
|
49
|
+
active: string
|
|
50
|
+
type: 'url'
|
|
51
|
+
columnName: string
|
|
52
|
+
showDropdown: boolean
|
|
53
|
+
filterStyle: string
|
|
54
|
+
label: string
|
|
55
|
+
order: 'asc' | 'desc' | 'cust'
|
|
56
|
+
values: string[]
|
|
57
|
+
queryParameter: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export type Legend = {
|
|
61
|
+
additionalCategories: string[]
|
|
62
|
+
// general legend onClick behavior
|
|
63
|
+
behavior: 'highlight' | 'isolate' | string
|
|
64
|
+
colorCode: string
|
|
65
|
+
description: string
|
|
66
|
+
// show or hide the legend
|
|
67
|
+
hide: boolean
|
|
68
|
+
highlightOnHover: boolean
|
|
69
|
+
label: string
|
|
70
|
+
lineMode: boolean
|
|
71
|
+
position: string
|
|
72
|
+
reverseLabelOrder: boolean
|
|
73
|
+
singleRow: boolean
|
|
74
|
+
type: string
|
|
75
|
+
verticalSorted: boolean
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
type Visual = {
|
|
79
|
+
border?: boolean
|
|
80
|
+
borderColorTheme?: boolean
|
|
81
|
+
accent?: boolean
|
|
82
|
+
background?: boolean
|
|
83
|
+
hideBackgroundColor?: boolean
|
|
84
|
+
verticalHoverLine?: boolean
|
|
85
|
+
horizontalHoverLine?: boolean
|
|
20
86
|
}
|
|
21
87
|
|
|
22
88
|
type AllChartsConfig = {
|
|
89
|
+
animate: boolean
|
|
90
|
+
general: General
|
|
91
|
+
barHasBorder: 'true' | 'false'
|
|
92
|
+
barHeight: number
|
|
93
|
+
barSpace: number
|
|
94
|
+
barStyle: string
|
|
95
|
+
barThickness: number
|
|
96
|
+
boxplot: BoxPlot
|
|
97
|
+
brush: {
|
|
98
|
+
active: boolean
|
|
99
|
+
height: number
|
|
100
|
+
}
|
|
101
|
+
chartMessage: { noData?: string }
|
|
102
|
+
color: string
|
|
103
|
+
colorMatchLineSeriesLabels: boolean
|
|
23
104
|
columns: ChartColumns
|
|
105
|
+
confidenceKeys: Record<string, any>
|
|
106
|
+
customColors: string[]
|
|
107
|
+
data: Object[]
|
|
108
|
+
dataUrl: string
|
|
109
|
+
dataCutoff: number
|
|
110
|
+
dataDescription: string
|
|
111
|
+
dataFormat: DataFormat
|
|
112
|
+
dataKey: string
|
|
113
|
+
description: string
|
|
114
|
+
dynamicMarginTop: number
|
|
115
|
+
exclusions: Exclusions
|
|
116
|
+
filters: Filter[]
|
|
117
|
+
filterBehavior: FilterBehavior
|
|
118
|
+
fontSize: 'small' | 'medium' | 'large'
|
|
119
|
+
footnotes: string
|
|
24
120
|
forestPlot: ForestPlotConfigSettings
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
121
|
+
formattedData: Object[] & { urlFiltered: boolean }
|
|
122
|
+
heights: {
|
|
123
|
+
vertical: number
|
|
28
124
|
}
|
|
125
|
+
highlightedBarValues: { value: any; color: string; borderWidth: number; legendLabel: string }[]
|
|
126
|
+
introText: string
|
|
127
|
+
isLollipopChart: boolean
|
|
128
|
+
isLegendValue: boolean
|
|
129
|
+
isResponsiveTicks: boolean
|
|
130
|
+
isPaletteReversed: boolean
|
|
131
|
+
labels: boolean
|
|
132
|
+
legend: Legend
|
|
133
|
+
lineDatapointColor: 'Same as Line' | 'Lighter than Line'
|
|
134
|
+
lineDatapointStyle: 'hidden' | 'always show' | 'hover'
|
|
135
|
+
lollipopColorStyle: 'regular' | 'two-tone'
|
|
136
|
+
lollipopShape: string
|
|
137
|
+
lollipopSize: 'small' | 'medium' | 'large'
|
|
138
|
+
newViz: Object
|
|
29
139
|
orientation: 'vertical' | 'horizontal'
|
|
30
|
-
|
|
31
|
-
|
|
140
|
+
palette: string
|
|
141
|
+
pieType?: string
|
|
142
|
+
primary?: DataFormat
|
|
143
|
+
roundingStyle: string
|
|
144
|
+
runtime: Runtime
|
|
145
|
+
runtimeDataUrl: string
|
|
146
|
+
series: Series
|
|
147
|
+
showLineSeriesLabels: boolean
|
|
148
|
+
showSidebar: boolean
|
|
149
|
+
showTitle: boolean
|
|
150
|
+
sortData: 'ascending' | 'descending'
|
|
151
|
+
stackedAreaChartLineType: string
|
|
152
|
+
suppressedData?: { label: string; icon: string; value: string }[]
|
|
153
|
+
superTitle: string
|
|
154
|
+
theme: string
|
|
155
|
+
table: Table
|
|
156
|
+
tipRounding: string
|
|
157
|
+
title: string
|
|
158
|
+
tooltips: {
|
|
159
|
+
singleSeries: boolean
|
|
160
|
+
opacity: number
|
|
161
|
+
dateDisplayFormat: string
|
|
162
|
+
}
|
|
163
|
+
topAxis: { hasLine: boolean }
|
|
164
|
+
twoColor: { palette: string }
|
|
165
|
+
type: string
|
|
32
166
|
useLogScale: boolean
|
|
33
|
-
|
|
167
|
+
visual: Visual
|
|
168
|
+
visualizationType: 'Area Chart' | 'Bar' | 'Box Plot' | 'Deviation Bar' | 'Forest Plot' | 'Line' | 'Paired Bar' | 'Pie' | 'Scatter Plot' | 'Spark Line' | 'Combo' | 'Forecasting'
|
|
169
|
+
visualizationSubType: string
|
|
170
|
+
xAxis: Axis
|
|
171
|
+
yAxis: Axis
|
|
34
172
|
xScale: Function
|
|
35
173
|
yScale: Function
|
|
174
|
+
regions: Region[]
|
|
36
175
|
}
|
|
37
176
|
|
|
177
|
+
export type ForestPlotConfig = {
|
|
178
|
+
visualizationType: 'Forest Plot'
|
|
179
|
+
forestPlot: ForestPlotConfigSettings
|
|
180
|
+
} & AllChartsConfig
|
|
181
|
+
|
|
38
182
|
export type LineChartConfig = {
|
|
39
183
|
visualizationType: 'Line'
|
|
40
184
|
lineDatapointStyle: 'hidden' | 'always show' | 'hover'
|
|
41
|
-
} &
|
|
185
|
+
} & AllChartsConfig
|
|
42
186
|
|
|
43
|
-
export type ChartConfig = LineChartConfig | AllChartsConfig
|
|
187
|
+
export type ChartConfig = LineChartConfig | ForestPlotConfig | AllChartsConfig
|
|
@@ -1,38 +1,60 @@
|
|
|
1
1
|
import { type ChartConfig } from './ChartConfig'
|
|
2
|
+
import { PickD3Scale } from '@visx/scale'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
export type ColorScale = PickD3Scale<'ordinal', any, any>
|
|
5
|
+
|
|
6
|
+
export type TransformedData = {
|
|
7
|
+
dataKey?: string
|
|
8
|
+
[key: string]: any
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type SharedChartContext = {
|
|
12
|
+
colorScale?: ColorScale
|
|
6
13
|
config: ChartConfig
|
|
14
|
+
currentViewport?: string
|
|
15
|
+
highlight?: Function
|
|
16
|
+
highlightReset?: Function
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Line Chart Specific Context
|
|
20
|
+
type LineChartContext = SharedChartContext & {
|
|
7
21
|
dimensions: [screenWidth: number, screenHeight: number]
|
|
8
22
|
formatDate: Function
|
|
23
|
+
formatTooltipsDate: Function
|
|
9
24
|
formatNumber: Function
|
|
10
25
|
handleLineType: Function
|
|
11
26
|
isNumber: unknown
|
|
27
|
+
isDebug?: boolean
|
|
12
28
|
parseDate: Function
|
|
13
29
|
rawData: Object[]
|
|
14
|
-
seriesHighlight:
|
|
30
|
+
seriesHighlight: string[]
|
|
15
31
|
tableData: Object[]
|
|
16
|
-
transformedData:
|
|
32
|
+
transformedData: TransformedData[]
|
|
17
33
|
updateConfig: Function
|
|
18
34
|
visualizationType: 'Line'
|
|
35
|
+
colorPalettes: Record<string, string[]>
|
|
36
|
+
twoColorPalette: Record<string, string[]>
|
|
19
37
|
}
|
|
20
38
|
|
|
21
39
|
export type ChartContext =
|
|
22
40
|
| LineChartContext
|
|
23
|
-
| {
|
|
24
|
-
colorScale?: Function
|
|
25
|
-
config?: ChartConfig
|
|
41
|
+
| (SharedChartContext & {
|
|
26
42
|
dimensions: [screenWidth: number, screenHeight: number]
|
|
27
|
-
|
|
28
43
|
formatDate?: Function
|
|
44
|
+
formatTooltipsDate: Function
|
|
29
45
|
formatNumber?: Function
|
|
30
46
|
handleLineType?: Function
|
|
31
47
|
isNumber?: boolean
|
|
48
|
+
// url param added to allow various console logs and chart helpers
|
|
49
|
+
isDebug?: boolean
|
|
32
50
|
parseDate?: Function
|
|
33
51
|
rawData?: Object[]
|
|
34
|
-
seriesHighlight?:
|
|
52
|
+
seriesHighlight?: string[]
|
|
35
53
|
tableData?: Object[]
|
|
36
|
-
transformedData?:
|
|
54
|
+
transformedData?: TransformedData[]
|
|
55
|
+
setSharedFilter?: Function
|
|
56
|
+
sharedFilterValue?: string
|
|
37
57
|
updateConfig?: Function
|
|
38
|
-
|
|
58
|
+
colorPalettes: any
|
|
59
|
+
twoColorPalette: any
|
|
60
|
+
})
|
package/src/types/ForestPlot.ts
CHANGED
|
@@ -2,8 +2,10 @@ import { type Color } from '@cdc/core/types/Color'
|
|
|
2
2
|
|
|
3
3
|
export type ForestPlotConfigSettings = {
|
|
4
4
|
colors: {
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
// color of line of no effect
|
|
6
|
+
line: Color
|
|
7
|
+
// color for effect estimate shape
|
|
8
|
+
shape: Color
|
|
7
9
|
}
|
|
8
10
|
// description - appears below the study column.
|
|
9
11
|
description: {
|
|
@@ -11,8 +13,9 @@ export type ForestPlotConfigSettings = {
|
|
|
11
13
|
text: string
|
|
12
14
|
location: number
|
|
13
15
|
}
|
|
14
|
-
// effect
|
|
15
|
-
estimateField: string
|
|
16
|
+
// column chose for the effect estimate
|
|
17
|
+
estimateField: string
|
|
18
|
+
// column chose for the esimate radius
|
|
16
19
|
estimateRadius: string
|
|
17
20
|
hideDateCategoryCol: boolean
|
|
18
21
|
leftWidthOffset: number
|
|
@@ -33,15 +36,8 @@ export type ForestPlotConfigSettings = {
|
|
|
33
36
|
radius: {
|
|
34
37
|
min: number
|
|
35
38
|
max: number
|
|
36
|
-
/** @deprecated - moved to estimateField due to duplication */
|
|
37
39
|
scalingColumn: string
|
|
38
40
|
}
|
|
39
|
-
/** @deprecated - moved to pooledResult */
|
|
40
|
-
regression: {
|
|
41
|
-
lower: number
|
|
42
|
-
upper: number
|
|
43
|
-
estimateField: number
|
|
44
|
-
}
|
|
45
41
|
result: {
|
|
46
42
|
show: boolean
|
|
47
43
|
text: string
|
|
@@ -51,9 +47,6 @@ export type ForestPlotConfigSettings = {
|
|
|
51
47
|
shape: string
|
|
52
48
|
startAt: number
|
|
53
49
|
title: string // centered title above the chart
|
|
54
|
-
|
|
55
|
-
/** @deprecated - moved to lineOfNoEffect*/
|
|
56
|
-
showZeroLine: boolean
|
|
57
50
|
// labels under chart
|
|
58
51
|
leftLabel: string
|
|
59
52
|
rightLabel: string
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
x,y1,y2,y3,y4
|
|
2
|
-
1000,8,37,72,82
|
|
3
|
-
2000,2,30,75,83
|
|
4
|
-
3000,15,42,51,95
|
|
5
|
-
4,10,38,61,96
|
|
6
|
-
5,1,38,66,86
|
|
7
|
-
60,6,37,70,85
|
|
8
|
-
10,19,47,59,91
|
|
9
|
-
24,18,32,68,89
|
|
10
|
-
3,7,38,74,89
|
|
11
|
-
26,10,39,56,91
|
|
12
|
-
42,16,38,55,76
|
|
13
|
-
32,20,46,52,94
|
|
14
|
-
11,9,41,57,86
|
|
15
|
-
22,10,47,56,80
|
|
16
|
-
73,1,36,71,94
|
|
17
|
-
23,13,30,66,78
|